Skip to content

Commit 6d232d3

Browse files
authored
Tests for the utbot maven plugin (#241)
1 parent b11d498 commit 6d232d3

File tree

11 files changed

+327
-20
lines changed

11 files changed

+327
-20
lines changed

gradle.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ eclipse_aether_version=1.1.0
3535
maven_wagon_version=3.5.1
3636
maven_plugin_api_version=3.8.5
3737
maven_plugin_tools_version=3.6.4
38+
maven_plugin_testing_version=3.3.0
39+
maven_resolver_api_version=1.8.0
40+
sisu_plexus_version=0.3.5
3841
javacpp_version=1.5.3
3942
jsoup_version=1.7.2
4043
djl_api_version=0.17.0

utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,12 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
214214
return UtTimeoutException(exception)
215215
}
216216
val instrs = traceHandler.computeInstructionList()
217-
val isNested = instrs.first().callId != instrs.last().callId
218-
return if (instrs.last().instructionData is ExplicitThrowInstruction) {
217+
val isNested = if (instrs.isEmpty()) {
218+
false
219+
} else {
220+
instrs.first().callId != instrs.last().callId
221+
}
222+
return if (instrs.isNotEmpty() && instrs.last().instructionData is ExplicitThrowInstruction) {
219223
UtExplicitlyThrownException(exception, isNested)
220224
} else {
221225
UtImplicitlyThrownException(exception, isNested)

utbot-framework/src/main/kotlin/org/utbot/framework/util/TestUtils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ data class GeneratedSarif(val text: String) {
6363
fun hasCodeFlows(): Boolean = text.contains("codeFlows")
6464

6565
fun codeFlowsIsNotEmpty(): Boolean = text.contains("threadFlows")
66+
67+
fun contains(value: String): Boolean = text.contains(value)
6668
}
6769

6870
fun compileClassAndGetClassPath(classNameToSource: Pair<String, String>): Pair<String, ClassLoader> {

utbot-maven/build.gradle

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,23 @@ dependencies {
1313
// `compile` because `api` dependencies are not included in pom.xml by `install` task
1414
compile project(':utbot-framework')
1515

16-
implementation "org.apache.maven:maven-core:${maven_plugin_api_version}"
17-
implementation "org.apache.maven:maven-plugin-api:${maven_plugin_api_version}"
18-
compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:${maven_plugin_tools_version}"
19-
implementation "io.github.microutils:kotlin-logging:${kotlin_logging_version}"
20-
21-
mavenEmbedder "org.apache.maven:maven-embedder:${maven_plugin_api_version}"
22-
mavenEmbedder "org.apache.maven:maven-compat:${maven_plugin_api_version}"
23-
mavenEmbedder "org.slf4j:slf4j-simple:${slf4j_version}"
24-
mavenEmbedder "org.eclipse.aether:aether-connector-basic:${eclipse_aether_version}"
25-
mavenEmbedder "org.eclipse.aether:aether-transport-wagon:${eclipse_aether_version}"
26-
mavenEmbedder "org.apache.maven.wagon:wagon-http:${maven_wagon_version}"
27-
mavenEmbedder "org.apache.maven.wagon:wagon-provider-api:${maven_wagon_version}"
16+
implementation "org.apache.maven:maven-core:$maven_plugin_api_version"
17+
implementation "org.apache.maven:maven-plugin-api:$maven_plugin_api_version"
18+
compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:$maven_plugin_tools_version"
19+
implementation "io.github.microutils:kotlin-logging:$kotlin_logging_version"
20+
21+
implementation "org.eclipse.sisu:org.eclipse.sisu.plexus:$sisu_plexus_version"
22+
testImplementation "org.apache.maven.plugin-testing:maven-plugin-testing-harness:$maven_plugin_testing_version"
23+
testImplementation "org.apache.maven:maven-compat:$maven_plugin_api_version"
24+
testImplementation "org.apache.maven.resolver:maven-resolver-api:$maven_resolver_api_version"
25+
26+
mavenEmbedder "org.apache.maven:maven-embedder:$maven_plugin_api_version"
27+
mavenEmbedder "org.apache.maven:maven-compat:$maven_plugin_api_version"
28+
mavenEmbedder "org.slf4j:slf4j-simple:$slf4j_version"
29+
mavenEmbedder "org.eclipse.aether:aether-connector-basic:$eclipse_aether_version"
30+
mavenEmbedder "org.eclipse.aether:aether-transport-wagon:$eclipse_aether_version"
31+
mavenEmbedder "org.apache.maven.wagon:wagon-http:$maven_wagon_version"
32+
mavenEmbedder "org.apache.maven.wagon:wagon-provider-api:$maven_wagon_version"
2833
}
2934

3035
/**

utbot-maven/src/main/kotlin/org/utbot/maven/plugin/GenerateTestsAndSarifReportMojo.kt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ internal val logger = KotlinLogging.logger {}
3434
)
3535
class GenerateTestsAndSarifReportMojo : AbstractMojo() {
3636

37+
/**
38+
* The maven project for which we are creating a SARIF report.
39+
*/
3740
@Parameter(defaultValue = "\${project}", readonly = true)
38-
private lateinit var mavenProject: MavenProject
41+
lateinit var mavenProject: MavenProject
3942

4043
/**
4144
* Classes for which the SARIF report will be created.
@@ -116,12 +119,23 @@ class GenerateTestsAndSarifReportMojo : AbstractMojo() {
116119
@Parameter(defaultValue = "")
117120
internal var classesToMockAlways: List<String> = listOf()
118121

122+
/**
123+
* Provides configuration needed to create a SARIF report.
124+
*/
125+
val sarifProperties: SarifMavenConfigurationProvider
126+
get() = SarifMavenConfigurationProvider(this)
127+
128+
/**
129+
* Contains information about the maven project for which we are creating a SARIF report.
130+
*/
131+
lateinit var rootMavenProjectWrapper: MavenProjectWrapper
132+
119133
/**
120134
* Entry point: called when the user starts this maven task.
121135
*/
122136
override fun execute() {
123-
val rootMavenProjectWrapper = try {
124-
MavenProjectWrapper(mavenProject, sarifProperties)
137+
try {
138+
rootMavenProjectWrapper = MavenProjectWrapper(mavenProject, sarifProperties)
125139
} catch (t: Throwable) {
126140
logger.error(t) { "Unexpected error while configuring the maven task" }
127141
return
@@ -140,9 +154,6 @@ class GenerateTestsAndSarifReportMojo : AbstractMojo() {
140154

141155
// internal
142156

143-
private val sarifProperties: SarifMavenConfigurationProvider
144-
get() = SarifMavenConfigurationProvider(this)
145-
146157
/**
147158
* Generates tests and a SARIF report for classes in the [mavenProjectWrapper] and in all its child projects.
148159
*/
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.utbot.maven.plugin
2+
3+
import org.apache.maven.plugin.testing.AbstractMojoTestCase
4+
import org.apache.maven.project.MavenProject
5+
import org.junit.jupiter.api.*
6+
import org.utbot.common.PathUtil.toPath
7+
import org.utbot.framework.util.GeneratedSarif
8+
import java.io.File
9+
10+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
11+
class GenerateTestsAndSarifReportMojoTest : AbstractMojoTestCase() {
12+
13+
@BeforeAll
14+
override fun setUp() {
15+
super.setUp()
16+
}
17+
18+
@AfterAll
19+
override fun tearDown() {
20+
super.tearDown()
21+
}
22+
23+
@Test
24+
fun `test directory exists and not empty`() {
25+
val testsRelativePath = sarifReportMojo.sarifProperties.generatedTestsRelativeRoot
26+
val testDirectory = testMavenProject.projectBaseDir.resolve(testsRelativePath)
27+
assert(directoryExistsAndNotEmpty(testDirectory))
28+
}
29+
30+
@Test
31+
fun `sarif directory exists and not empty`() {
32+
val reportsRelativePath = sarifReportMojo.sarifProperties.sarifReportsRelativeRoot
33+
val sarifDirectory = testMavenProject.projectBaseDir.resolve(reportsRelativePath)
34+
assert(directoryExistsAndNotEmpty(sarifDirectory))
35+
}
36+
37+
@Test
38+
fun `sarif report contains all required results`() {
39+
val sarifReportFile = sarifReportMojo.rootMavenProjectWrapper.sarifReportFile
40+
val sarifReportText = sarifReportFile.readText()
41+
GeneratedSarif(sarifReportText).apply {
42+
assert(hasSchema())
43+
assert(hasVersion())
44+
assert(hasRules())
45+
assert(hasResults())
46+
assert(hasCodeFlows())
47+
assert(codeFlowsIsNotEmpty())
48+
assert(contains("ArithmeticException"))
49+
}
50+
}
51+
52+
// internal
53+
54+
private val testMavenProject: TestMavenProject =
55+
TestMavenProject("src/test/resources/project-to-test".toPath())
56+
57+
private val sarifReportMojo by lazy {
58+
configureSarifReportMojo(testMavenProject.mavenProject).apply {
59+
this.execute()
60+
}
61+
}
62+
63+
private fun configureSarifReportMojo(mavenProject: MavenProject): GenerateTestsAndSarifReportMojo {
64+
val generateTestsAndSarifReportMojo = configureMojo(
65+
GenerateTestsAndSarifReportMojo(), "utbot-maven", mavenProject.file
66+
) as GenerateTestsAndSarifReportMojo
67+
generateTestsAndSarifReportMojo.mavenProject = mavenProject
68+
return generateTestsAndSarifReportMojo
69+
}
70+
71+
private fun directoryExistsAndNotEmpty(directory: File): Boolean =
72+
directory.exists() && directory.isDirectory && directory.list()?.isNotEmpty() == true
73+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.utbot.maven.plugin
2+
3+
import org.apache.commons.lang3.reflect.FieldUtils
4+
import org.apache.maven.model.io.xpp3.MavenXpp3Reader
5+
import org.apache.maven.project.MavenProject
6+
import org.codehaus.plexus.util.FileUtils
7+
import java.io.File
8+
import java.io.FileReader
9+
import java.nio.file.Path
10+
11+
/**
12+
* Wrapper for the maven project stored in the test resources.
13+
*/
14+
class TestMavenProject(pathToProject: Path) {
15+
16+
/**
17+
* Path to the copied maven project.
18+
*/
19+
val projectBaseDir =
20+
File("build/resources/${pathToProject.fileName}")
21+
22+
init {
23+
projectBaseDir.deleteRecursively()
24+
// copying the project to the build directory to change it there
25+
FileUtils.copyDirectoryStructure(pathToProject.toFile(), projectBaseDir)
26+
}
27+
28+
val mavenProject: MavenProject = run {
29+
val pomFile = File(projectBaseDir, "pom.xml")
30+
val model = MavenXpp3Reader().read(FileReader(pomFile))
31+
val mavenProject = MavenProject(model)
32+
mavenProject.setPomFile(pomFile)
33+
mavenProject.collectedProjects = listOf() // no child modules
34+
mavenProject.addCompileSourceRoot(mavenProject.build.sourceDirectory)
35+
FieldUtils.writeField(mavenProject, "basedir", projectBaseDir, true)
36+
mavenProject
37+
}
38+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package org.utbot.maven.plugin.extension
2+
3+
import org.apache.maven.plugin.testing.AbstractMojoTestCase
4+
import org.apache.maven.project.MavenProject
5+
import org.junit.jupiter.api.*
6+
import org.utbot.common.PathUtil.toPath
7+
import org.utbot.engine.Mocker
8+
import org.utbot.framework.codegen.*
9+
import org.utbot.framework.plugin.api.ClassId
10+
import org.utbot.framework.plugin.api.CodegenLanguage
11+
import org.utbot.framework.plugin.api.MockFramework
12+
import org.utbot.framework.plugin.api.MockStrategyApi
13+
import org.utbot.maven.plugin.GenerateTestsAndSarifReportMojo
14+
import org.utbot.maven.plugin.TestMavenProject
15+
import java.io.File
16+
17+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
18+
class SarifMavenConfigurationProviderTest : AbstractMojoTestCase() {
19+
20+
@BeforeAll
21+
override fun setUp() {
22+
super.setUp()
23+
}
24+
25+
@AfterAll
26+
override fun tearDown() {
27+
super.tearDown()
28+
}
29+
30+
@Test
31+
fun `targetClasses should be provided from the configuration`() {
32+
Assertions.assertEquals(listOf("Main"), configurationProvider.targetClasses)
33+
}
34+
35+
@Test
36+
fun `projectRoot should be provided from the configuration`() {
37+
Assertions.assertEquals(File("build/resources/project-to-test"), configurationProvider.projectRoot)
38+
}
39+
40+
@Test
41+
fun `generatedTestsRelativeRoot should be provided from the configuration`() {
42+
Assertions.assertEquals("target/generated/test", configurationProvider.generatedTestsRelativeRoot)
43+
}
44+
45+
@Test
46+
fun `sarifReportsRelativeRoot should be provided from the configuration`() {
47+
Assertions.assertEquals("target/generated/sarif", configurationProvider.sarifReportsRelativeRoot)
48+
}
49+
50+
@Test
51+
fun `markGeneratedTestsDirectoryAsTestSourcesRoot should be provided from the configuration`() {
52+
Assertions.assertEquals(true, configurationProvider.markGeneratedTestsDirectoryAsTestSourcesRoot)
53+
}
54+
55+
@Test
56+
fun `testFramework should be provided from the configuration`() {
57+
Assertions.assertEquals(Junit5, configurationProvider.testFramework)
58+
}
59+
60+
61+
@Test
62+
fun `mockFramework should be provided from the configuration`() {
63+
Assertions.assertEquals(MockFramework.MOCKITO, configurationProvider.mockFramework)
64+
}
65+
66+
67+
@Test
68+
fun `generationTimeout should be provided from the configuration`() {
69+
Assertions.assertEquals(10000, configurationProvider.generationTimeout)
70+
}
71+
72+
@Test
73+
fun `codegenLanguage should be provided from the configuration`() {
74+
Assertions.assertEquals(CodegenLanguage.JAVA, configurationProvider.codegenLanguage)
75+
}
76+
77+
@Test
78+
fun `mockStrategy should be provided from the configuration`() {
79+
Assertions.assertEquals(MockStrategyApi.OTHER_PACKAGES, configurationProvider.mockStrategy)
80+
}
81+
82+
@Test
83+
fun `staticsMocking should be provided from the configuration`() {
84+
Assertions.assertEquals(MockitoStaticMocking, configurationProvider.staticsMocking)
85+
}
86+
87+
@Test
88+
fun `forceStaticMocking should be provided from the configuration`() {
89+
Assertions.assertEquals(ForceStaticMocking.FORCE, configurationProvider.forceStaticMocking)
90+
}
91+
92+
@Test
93+
fun `classesToMockAlways should be provided from the configuration`() {
94+
val expectedClassesToMockAlways =
95+
(Mocker.defaultSuperClassesToMockAlwaysNames + "java.io.File").map(::ClassId).toSet()
96+
Assertions.assertEquals(expectedClassesToMockAlways, configurationProvider.classesToMockAlways)
97+
}
98+
99+
// internal
100+
101+
private val testMavenProject: TestMavenProject =
102+
TestMavenProject("src/test/resources/project-to-test".toPath())
103+
104+
private val sarifReportMojo by lazy {
105+
configureSarifReportMojo(testMavenProject.mavenProject)
106+
}
107+
108+
private val configurationProvider by lazy {
109+
sarifReportMojo.sarifProperties
110+
}
111+
112+
private fun configureSarifReportMojo(mavenProject: MavenProject): GenerateTestsAndSarifReportMojo {
113+
val generateTestsAndSarifReportMojo = configureMojo(
114+
GenerateTestsAndSarifReportMojo(), "utbot-maven", mavenProject.file
115+
) as GenerateTestsAndSarifReportMojo
116+
generateTestsAndSarifReportMojo.mavenProject = mavenProject
117+
return generateTestsAndSarifReportMojo
118+
}
119+
}

0 commit comments

Comments
 (0)