Skip to content

Commit f84ab2a

Browse files
author
Nikita Stroganov
committed
#240 Tests for the utbot maven plugin
1 parent 36aa0bd commit f84ab2a

10 files changed

Lines changed: 311 additions & 8 deletions

File tree

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,11 @@ 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+
return if (instrs.isNotEmpty() && instrs.last().instructionData is ExplicitThrowInstruction) {
219222
UtExplicitlyThrownException(exception, isNested)
220223
} else {
221224
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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ dependencies {
1818
compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:${maven_plugin_tools_version}"
1919
implementation "io.github.microutils:kotlin-logging:${kotlin_logging_version}"
2020

21+
implementation 'org.eclipse.sisu:org.eclipse.sisu.plexus:0.3.5'
22+
testImplementation 'junit:junit:4.13.2'
23+
testImplementation "org.apache.maven.plugin-testing:maven-plugin-testing-harness:3.3.0"
24+
testImplementation 'org.apache.maven:maven-compat:3.8.5'
25+
testImplementation 'org.apache.maven.resolver:maven-resolver-api:1.8.0'
26+
2127
mavenEmbedder "org.apache.maven:maven-embedder:${maven_plugin_api_version}"
2228
mavenEmbedder "org.apache.maven:maven-compat:${maven_plugin_api_version}"
2329
mavenEmbedder "org.slf4j:slf4j-simple:${slf4j_version}"

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal val logger = KotlinLogging.logger {}
3535
class GenerateTestsAndSarifReportMojo : AbstractMojo() {
3636

3737
@Parameter(defaultValue = "\${project}", readonly = true)
38-
private lateinit var mavenProject: MavenProject
38+
lateinit var mavenProject: MavenProject
3939

4040
/**
4141
* Classes for which the SARIF report will be created.
@@ -116,12 +116,23 @@ class GenerateTestsAndSarifReportMojo : AbstractMojo() {
116116
@Parameter(defaultValue = "")
117117
internal var classesToMockAlways: List<String> = listOf()
118118

119+
/**
120+
* Provides configuration needed to create a SARIF report.
121+
*/
122+
val sarifProperties: SarifMavenConfigurationProvider
123+
get() = SarifMavenConfigurationProvider(this)
124+
125+
/**
126+
* Contains information about the maven project for which we are creating a SARIF report.
127+
*/
128+
lateinit var rootMavenProjectWrapper: MavenProjectWrapper
129+
119130
/**
120131
* Entry point: called when the user starts this maven task.
121132
*/
122133
override fun execute() {
123-
val rootMavenProjectWrapper = try {
124-
MavenProjectWrapper(mavenProject, sarifProperties)
134+
try {
135+
rootMavenProjectWrapper = MavenProjectWrapper(mavenProject, sarifProperties)
125136
} catch (t: Throwable) {
126137
logger.error(t) { "Unexpected error while configuring the maven task" }
127138
return
@@ -140,9 +151,6 @@ class GenerateTestsAndSarifReportMojo : AbstractMojo() {
140151

141152
// internal
142153

143-
private val sarifProperties: SarifMavenConfigurationProvider
144-
get() = SarifMavenConfigurationProvider(this)
145-
146154
/**
147155
* Generates tests and a SARIF report for classes in the [mavenProjectWrapper] and in all its child projects.
148156
*/
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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 by lazy {
55+
TestMavenProject("src/test/resources/project-to-test".toPath())
56+
}
57+
58+
private val sarifReportMojo by lazy {
59+
configureSarifReportMojo(testMavenProject.mavenProject).apply {
60+
this.execute()
61+
}
62+
}
63+
64+
private fun configureSarifReportMojo(mavenProject: MavenProject): GenerateTestsAndSarifReportMojo {
65+
val generateTestsAndSarifReportMojo = configureMojo(
66+
GenerateTestsAndSarifReportMojo(), "utbot-maven", mavenProject.file
67+
) as GenerateTestsAndSarifReportMojo
68+
generateTestsAndSarifReportMojo.mavenProject = mavenProject
69+
return generateTestsAndSarifReportMojo
70+
}
71+
72+
private fun directoryExistsAndNotEmpty(directory: File): Boolean =
73+
directory.exists() && directory.isDirectory && directory.list()?.isNotEmpty() == true
74+
}
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 by lazy {
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: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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 by lazy {
102+
TestMavenProject("src/test/resources/project-to-test".toPath())
103+
}
104+
105+
private val sarifReportMojo by lazy {
106+
configureSarifReportMojo(testMavenProject.mavenProject)
107+
}
108+
109+
private val configurationProvider by lazy {
110+
sarifReportMojo.sarifProperties
111+
}
112+
113+
private fun configureSarifReportMojo(mavenProject: MavenProject): GenerateTestsAndSarifReportMojo {
114+
val generateTestsAndSarifReportMojo = configureMojo(
115+
GenerateTestsAndSarifReportMojo(), "utbot-maven", mavenProject.file
116+
) as GenerateTestsAndSarifReportMojo
117+
generateTestsAndSarifReportMojo.mavenProject = mavenProject
118+
return generateTestsAndSarifReportMojo
119+
}
120+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<groupId>org.example</groupId>
7+
<artifactId>project-to-test</artifactId>
8+
<version>1.0</version>
9+
10+
<properties>
11+
<maven.compiler.source>8</maven.compiler.source>
12+
<maven.compiler.target>8</maven.compiler.target>
13+
</properties>
14+
15+
<build>
16+
<!-- relative to 'utbot-maven' -->
17+
<sourceDirectory>build/resources/project-to-test/src/main/java</sourceDirectory>
18+
<outputDirectory>build/resources/project-to-test/target/classes</outputDirectory>
19+
20+
<plugins>
21+
<plugin>
22+
<groupId>org.utbot</groupId>
23+
<artifactId>utbot-maven</artifactId>
24+
<version>1.0-SNAPSHOT</version>
25+
<configuration>
26+
<targetClasses>
27+
<param>Main</param>
28+
</targetClasses>
29+
<projectRoot>build/resources/project-to-test</projectRoot>
30+
<generatedTestsRelativeRoot>target/generated/test</generatedTestsRelativeRoot>
31+
<sarifReportsRelativeRoot>target/generated/sarif</sarifReportsRelativeRoot>
32+
<markGeneratedTestsDirectoryAsTestSourcesRoot>true</markGeneratedTestsDirectoryAsTestSourcesRoot>
33+
<testFramework>junit5</testFramework>
34+
<mockFramework>mockito</mockFramework>
35+
<generationTimeout>10000</generationTimeout>
36+
<codegenLanguage>java</codegenLanguage>
37+
<mockStrategy>package-based</mockStrategy>
38+
<staticsMocking>mock-statics</staticsMocking>
39+
<forceStaticMocking>force</forceStaticMocking>
40+
<classesToMockAlways>
41+
<param>java.io.File</param>
42+
</classesToMockAlways>
43+
</configuration>
44+
</plugin>
45+
</plugins>
46+
</build>
47+
</project>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class Main {
2+
public int f(int a) {
3+
return 1 / a;
4+
}
5+
}
Binary file not shown.

0 commit comments

Comments
 (0)