Skip to content

Commit bd31da7

Browse files
authored
Go support (#1757)
1 parent 2d22922 commit bd31da7

File tree

75 files changed

+5958
-8
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+5958
-8
lines changed

gradle.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ideVersion=222.4167.29
77

88
pythonIde=IC,IU,PC,PY
99
jsIde=IU,PY,WS
10+
goIde=IU
1011

1112
# In order to run Android Studion instead of Intellij Community, specify the path to your Android Studio installation
1213
#androidStudioPath=your_path_to_android_studio
@@ -15,6 +16,9 @@ jsIde=IU,PY,WS
1516
pythonCommunityPluginVersion=222.4167.37
1617
pythonUltimatePluginVersion=222.4167.37
1718

19+
# Version numbers: https://plugins.jetbrains.com/plugin/9568-go/versions
20+
goPluginVersion=222.4167.21
21+
1822
kotlinPluginVersion=222-1.7.20-release-201-IJ4167.29
1923

2024
junit5Version=5.8.0-RC1

settings.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ val ideType: String by settings
33
val pythonIde: String by settings
44
val jsIde: String by settings
55
val includeRiderInBuild: String by settings
6+
val goIde: String by settings
67

78
pluginManagement {
89
resolutionStrategy {
@@ -59,3 +60,9 @@ if (jsIde.split(",").contains(ideType)) {
5960
include("utbot-cli-js")
6061
include("utbot-intellij-js")
6162
}
63+
64+
if (goIde.split(",").contains(ideType)) {
65+
include("utbot-go")
66+
include("utbot-cli-go")
67+
include("utbot-intellij-go")
68+
}

utbot-cli-go/build.gradle

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
2+
kotlinOptions {
3+
jvmTarget = JavaVersion.VERSION_11
4+
freeCompilerArgs += ["-Xallow-result-return-type", "-Xsam-conversions=class"]
5+
}
6+
}
7+
8+
tasks.withType(JavaCompile) {
9+
sourceCompatibility = JavaVersion.VERSION_1_8
10+
targetCompatibility = JavaVersion.VERSION_11
11+
}
12+
13+
configurations {
14+
fetchInstrumentationJar
15+
}
16+
17+
dependencies {
18+
implementation project(':utbot-framework')
19+
implementation project(':utbot-cli')
20+
implementation project(':utbot-go')
21+
22+
// Without this dependency testng tests do not run.
23+
implementation group: 'com.beust', name: 'jcommander', version: '1.48'
24+
implementation group: 'org.junit.platform', name: 'junit-platform-console-standalone', version: junit4PlatformVersion
25+
implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlinLoggingVersion
26+
implementation group: 'com.github.ajalt.clikt', name: 'clikt', version: cliktVersion
27+
implementation group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: junit5Version
28+
implementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junit5Version
29+
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: log4j2Version
30+
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: log4j2Version
31+
implementation group: 'org.jacoco', name: 'org.jacoco.report', version: jacocoVersion
32+
//noinspection GroovyAssignabilityCheck
33+
fetchInstrumentationJar project(path: ':utbot-instrumentation', configuration: 'instrumentationArchive')
34+
35+
implementation 'com.beust:klaxon:5.5' // to read and write JSON
36+
}
37+
38+
processResources {
39+
from(configurations.fetchInstrumentationJar) {
40+
into "lib"
41+
}
42+
}
43+
44+
task createProperties(dependsOn: processResources) {
45+
doLast {
46+
new File("$buildDir/resources/main/version.properties").withWriter { w ->
47+
Properties properties = new Properties()
48+
//noinspection GroovyAssignabilityCheck
49+
properties['version'] = project.version.toString()
50+
properties.store w, null
51+
}
52+
}
53+
}
54+
55+
classes {
56+
dependsOn createProperties
57+
}
58+
59+
jar {
60+
manifest {
61+
attributes 'Main-Class': 'org.utbot.cli.go.ApplicationKt'
62+
attributes 'Bundle-SymbolicName': 'org.utbot.cli.go'
63+
attributes 'Bundle-Version': "${project.version}"
64+
attributes 'Implementation-Title': 'UtBot Go CLI'
65+
attributes 'JAR-Type': 'Fat JAR'
66+
}
67+
68+
archiveVersion.set(project.version as String)
69+
70+
dependsOn configurations.runtimeClasspath
71+
from {
72+
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
73+
}
74+
75+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
76+
}
77+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.utbot.cli.go
2+
3+
import com.github.ajalt.clikt.core.CliktCommand
4+
import com.github.ajalt.clikt.core.subcommands
5+
import com.github.ajalt.clikt.parameters.options.default
6+
import com.github.ajalt.clikt.parameters.options.option
7+
import com.github.ajalt.clikt.parameters.options.versionOption
8+
import com.github.ajalt.clikt.parameters.types.enum
9+
import org.slf4j.event.Level
10+
import org.utbot.cli.getVersion
11+
import org.utbot.cli.setVerbosity
12+
import kotlin.system.exitProcess
13+
import org.utbot.cli.go.commands.GenerateGoTestsCommand
14+
import org.utbot.cli.go.commands.RunGoTestsCommand
15+
16+
class UtBotCli : CliktCommand(name = "UnitTestBot Go Command Line Interface") {
17+
private val verbosity by option("--verbosity", help = "Changes verbosity level, case insensitive")
18+
.enum<Level>(ignoreCase = true)
19+
.default(Level.INFO)
20+
21+
override fun run() = setVerbosity(verbosity)
22+
23+
init {
24+
versionOption(getVersion())
25+
}
26+
}
27+
28+
fun main(args: Array<String>) = try {
29+
UtBotCli().subcommands(
30+
GenerateGoTestsCommand(),
31+
RunGoTestsCommand(),
32+
).main(args)
33+
} catch (ex: Throwable) {
34+
ex.printStackTrace()
35+
exitProcess(1)
36+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.utbot.cli.go.commands
2+
3+
import com.beust.klaxon.Json
4+
5+
internal data class Position(@Json(index = 1) val line: Int, @Json(index = 2) val column: Int)
6+
7+
internal data class CodeRegion(@Json(index = 1) val start: Position, @Json(index = 2) val end: Position)
8+
9+
internal data class CoveredSourceFile(
10+
@Json(index = 1) val sourceFileName: String,
11+
@Json(index = 2) val covered: List<CodeRegion>,
12+
@Json(index = 3) val uncovered: List<CodeRegion>
13+
)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package org.utbot.cli.go.commands
2+
3+
import com.github.ajalt.clikt.core.CliktCommand
4+
import com.github.ajalt.clikt.parameters.options.*
5+
import com.github.ajalt.clikt.parameters.types.long
6+
import mu.KotlinLogging
7+
import org.utbot.cli.go.logic.CliGoUtTestsGenerationController
8+
import org.utbot.cli.go.util.durationInMillis
9+
import org.utbot.cli.go.util.now
10+
import org.utbot.cli.go.util.toAbsolutePath
11+
import org.utbot.go.logic.GoUtTestsGenerationConfig
12+
import java.nio.file.Files
13+
import java.nio.file.Paths
14+
15+
private val logger = KotlinLogging.logger {}
16+
17+
class GenerateGoTestsCommand :
18+
CliktCommand(name = "generateGo", help = "Generates tests for the specified Go source file") {
19+
20+
private val sourceFile: String by option(
21+
"-s", "--source",
22+
help = "Specifies Go source file to generate tests for"
23+
)
24+
.required()
25+
.check("Must exist and ends with *.go suffix") {
26+
it.endsWith(".go") && Files.exists(Paths.get(it))
27+
}
28+
29+
private val selectedFunctionsNames: List<String> by option(
30+
"-f", "--function",
31+
help = StringBuilder()
32+
.append("Specifies function name to generate tests for. ")
33+
.append("Can be used multiple times to select multiple functions at the same time.")
34+
.toString()
35+
)
36+
.multiple(required = true)
37+
38+
private val goExecutablePath: String by option(
39+
"-go", "--go-path",
40+
help = "Specifies path to Go executable. For example, it could be [/usr/local/go/bin/go] for some systems"
41+
)
42+
.required() // TODO: attempt to find it if not specified
43+
44+
private val eachFunctionExecutionTimeoutMillis: Long by option(
45+
"-et", "--each-execution-timeout",
46+
help = StringBuilder()
47+
.append("Specifies a timeout in milliseconds for each fuzzed function execution.")
48+
.append("Default is ${GoUtTestsGenerationConfig.DEFAULT_EACH_EXECUTION_TIMEOUT_MILLIS} ms")
49+
.toString()
50+
)
51+
.long()
52+
.default(GoUtTestsGenerationConfig.DEFAULT_EACH_EXECUTION_TIMEOUT_MILLIS)
53+
.check("Must be positive") { it > 0 }
54+
55+
private val allFunctionExecutionTimeoutMillis: Long by option(
56+
"-at", "--all-execution-timeout",
57+
help = StringBuilder()
58+
.append("Specifies a timeout in milliseconds for all fuzzed function execution.")
59+
.append("Default is ${GoUtTestsGenerationConfig.DEFAULT_ALL_EXECUTION_TIMEOUT_MILLIS} ms")
60+
.toString()
61+
)
62+
.long()
63+
.default(GoUtTestsGenerationConfig.DEFAULT_ALL_EXECUTION_TIMEOUT_MILLIS)
64+
.check("Must be positive") { it > 0 }
65+
66+
private val printToStdOut: Boolean by option(
67+
"-p",
68+
"--print-test",
69+
help = "Specifies whether a test should be printed out to StdOut. Is disabled by default"
70+
)
71+
.flag(default = false)
72+
73+
private val overwriteTestFiles: Boolean by option(
74+
"-w",
75+
"--overwrite",
76+
help = "Specifies whether to overwrite the output test file if it already exists. Is disabled by default"
77+
)
78+
.flag(default = false)
79+
80+
override fun run() {
81+
val sourceFileAbsolutePath = sourceFile.toAbsolutePath()
82+
val goExecutableAbsolutePath = goExecutablePath.toAbsolutePath()
83+
84+
val testsGenerationStarted = now()
85+
logger.info { "Test file generation for [$sourceFile] - started" }
86+
try {
87+
CliGoUtTestsGenerationController(
88+
printToStdOut = printToStdOut,
89+
overwriteTestFiles = overwriteTestFiles
90+
).generateTests(
91+
mapOf(sourceFileAbsolutePath to selectedFunctionsNames),
92+
GoUtTestsGenerationConfig(
93+
goExecutableAbsolutePath,
94+
eachFunctionExecutionTimeoutMillis,
95+
allFunctionExecutionTimeoutMillis
96+
)
97+
)
98+
} catch (t: Throwable) {
99+
logger.error { "An error has occurred while generating test for snippet $sourceFile: $t" }
100+
throw t
101+
} finally {
102+
val duration = durationInMillis(testsGenerationStarted)
103+
logger.info { "Test file generation for [$sourceFile] - completed in [$duration] (ms)" }
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)