Skip to content
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
3 changes: 3 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ eclipse_aether_version=1.1.0
maven_wagon_version=3.5.1
maven_plugin_api_version=3.8.5
maven_plugin_tools_version=3.6.4
maven_plugin_testing_version=3.3.0
maven_resolver_api_version=1.8.0
sisu_plexus_version=0.3.5
javacpp_version=1.5.3
jsoup_version=1.7.2
djl_api_version=0.17.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,12 @@ object UtExecutionInstrumentation : Instrumentation<UtConcreteExecutionResult> {
return UtTimeoutException(exception)
}
val instrs = traceHandler.computeInstructionList()
val isNested = instrs.first().callId != instrs.last().callId
return if (instrs.last().instructionData is ExplicitThrowInstruction) {
val isNested = if (instrs.isEmpty()) {
false
} else {
instrs.first().callId != instrs.last().callId
Comment thread
mmvpm marked this conversation as resolved.
}
return if (instrs.isNotEmpty() && instrs.last().instructionData is ExplicitThrowInstruction) {
UtExplicitlyThrownException(exception, isNested)
} else {
UtImplicitlyThrownException(exception, isNested)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ data class GeneratedSarif(val text: String) {
fun hasCodeFlows(): Boolean = text.contains("codeFlows")

fun codeFlowsIsNotEmpty(): Boolean = text.contains("threadFlows")

fun contains(value: String): Boolean = text.contains(value)
}

fun compileClassAndGetClassPath(classNameToSource: Pair<String, String>): Pair<String, ClassLoader> {
Expand Down
29 changes: 17 additions & 12 deletions utbot-maven/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ dependencies {
// `compile` because `api` dependencies are not included in pom.xml by `install` task
compile project(':utbot-framework')

implementation "org.apache.maven:maven-core:${maven_plugin_api_version}"
implementation "org.apache.maven:maven-plugin-api:${maven_plugin_api_version}"
compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:${maven_plugin_tools_version}"
implementation "io.github.microutils:kotlin-logging:${kotlin_logging_version}"

mavenEmbedder "org.apache.maven:maven-embedder:${maven_plugin_api_version}"
mavenEmbedder "org.apache.maven:maven-compat:${maven_plugin_api_version}"
mavenEmbedder "org.slf4j:slf4j-simple:${slf4j_version}"
mavenEmbedder "org.eclipse.aether:aether-connector-basic:${eclipse_aether_version}"
mavenEmbedder "org.eclipse.aether:aether-transport-wagon:${eclipse_aether_version}"
mavenEmbedder "org.apache.maven.wagon:wagon-http:${maven_wagon_version}"
mavenEmbedder "org.apache.maven.wagon:wagon-provider-api:${maven_wagon_version}"
implementation "org.apache.maven:maven-core:$maven_plugin_api_version"
implementation "org.apache.maven:maven-plugin-api:$maven_plugin_api_version"
compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:$maven_plugin_tools_version"
implementation "io.github.microutils:kotlin-logging:$kotlin_logging_version"

implementation "org.eclipse.sisu:org.eclipse.sisu.plexus:$sisu_plexus_version"
testImplementation "org.apache.maven.plugin-testing:maven-plugin-testing-harness:$maven_plugin_testing_version"
testImplementation "org.apache.maven:maven-compat:$maven_plugin_api_version"
testImplementation "org.apache.maven.resolver:maven-resolver-api:$maven_resolver_api_version"

mavenEmbedder "org.apache.maven:maven-embedder:$maven_plugin_api_version"
mavenEmbedder "org.apache.maven:maven-compat:$maven_plugin_api_version"
mavenEmbedder "org.slf4j:slf4j-simple:$slf4j_version"
mavenEmbedder "org.eclipse.aether:aether-connector-basic:$eclipse_aether_version"
mavenEmbedder "org.eclipse.aether:aether-transport-wagon:$eclipse_aether_version"
mavenEmbedder "org.apache.maven.wagon:wagon-http:$maven_wagon_version"
mavenEmbedder "org.apache.maven.wagon:wagon-provider-api:$maven_wagon_version"
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ internal val logger = KotlinLogging.logger {}
)
class GenerateTestsAndSarifReportMojo : AbstractMojo() {

/**
* The maven project for which we are creating a SARIF report.
*/
@Parameter(defaultValue = "\${project}", readonly = true)
private lateinit var mavenProject: MavenProject
lateinit var mavenProject: MavenProject
Comment thread
mmvpm marked this conversation as resolved.

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

/**
* Provides configuration needed to create a SARIF report.
*/
val sarifProperties: SarifMavenConfigurationProvider
get() = SarifMavenConfigurationProvider(this)

/**
* Contains information about the maven project for which we are creating a SARIF report.
*/
lateinit var rootMavenProjectWrapper: MavenProjectWrapper

/**
* Entry point: called when the user starts this maven task.
*/
override fun execute() {
val rootMavenProjectWrapper = try {
MavenProjectWrapper(mavenProject, sarifProperties)
try {
rootMavenProjectWrapper = MavenProjectWrapper(mavenProject, sarifProperties)
} catch (t: Throwable) {
logger.error(t) { "Unexpected error while configuring the maven task" }
return
Expand All @@ -140,9 +154,6 @@ class GenerateTestsAndSarifReportMojo : AbstractMojo() {

// internal

private val sarifProperties: SarifMavenConfigurationProvider
get() = SarifMavenConfigurationProvider(this)

/**
* Generates tests and a SARIF report for classes in the [mavenProjectWrapper] and in all its child projects.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.utbot.maven.plugin

import org.apache.maven.plugin.testing.AbstractMojoTestCase
import org.apache.maven.project.MavenProject
import org.junit.jupiter.api.*
import org.utbot.common.PathUtil.toPath
import org.utbot.framework.util.GeneratedSarif
import java.io.File

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class GenerateTestsAndSarifReportMojoTest : AbstractMojoTestCase() {

@BeforeAll
override fun setUp() {
super.setUp()
}

@AfterAll
override fun tearDown() {
super.tearDown()
}

@Test
fun `test directory exists and not empty`() {
val testsRelativePath = sarifReportMojo.sarifProperties.generatedTestsRelativeRoot
val testDirectory = testMavenProject.projectBaseDir.resolve(testsRelativePath)
assert(directoryExistsAndNotEmpty(testDirectory))
}

@Test
fun `sarif directory exists and not empty`() {
val reportsRelativePath = sarifReportMojo.sarifProperties.sarifReportsRelativeRoot
val sarifDirectory = testMavenProject.projectBaseDir.resolve(reportsRelativePath)
assert(directoryExistsAndNotEmpty(sarifDirectory))
}

@Test
fun `sarif report contains all required results`() {
val sarifReportFile = sarifReportMojo.rootMavenProjectWrapper.sarifReportFile
val sarifReportText = sarifReportFile.readText()
GeneratedSarif(sarifReportText).apply {
assert(hasSchema())
assert(hasVersion())
assert(hasRules())
assert(hasResults())
assert(hasCodeFlows())
assert(codeFlowsIsNotEmpty())
assert(contains("ArithmeticException"))
}
}

// internal

private val testMavenProject: TestMavenProject =
TestMavenProject("src/test/resources/project-to-test".toPath())

private val sarifReportMojo by lazy {
configureSarifReportMojo(testMavenProject.mavenProject).apply {
this.execute()
}
}

private fun configureSarifReportMojo(mavenProject: MavenProject): GenerateTestsAndSarifReportMojo {
val generateTestsAndSarifReportMojo = configureMojo(
GenerateTestsAndSarifReportMojo(), "utbot-maven", mavenProject.file
) as GenerateTestsAndSarifReportMojo
generateTestsAndSarifReportMojo.mavenProject = mavenProject
return generateTestsAndSarifReportMojo
}

private fun directoryExistsAndNotEmpty(directory: File): Boolean =
directory.exists() && directory.isDirectory && directory.list()?.isNotEmpty() == true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.utbot.maven.plugin

import org.apache.commons.lang3.reflect.FieldUtils
import org.apache.maven.model.io.xpp3.MavenXpp3Reader
import org.apache.maven.project.MavenProject
import org.codehaus.plexus.util.FileUtils
import java.io.File
import java.io.FileReader
import java.nio.file.Path

/**
* Wrapper for the maven project stored in the test resources.
*/
class TestMavenProject(pathToProject: Path) {

/**
* Path to the copied maven project.
*/
val projectBaseDir =
File("build/resources/${pathToProject.fileName}")

init {
projectBaseDir.deleteRecursively()
// copying the project to the build directory to change it there
FileUtils.copyDirectoryStructure(pathToProject.toFile(), projectBaseDir)
}

val mavenProject: MavenProject = run {
val pomFile = File(projectBaseDir, "pom.xml")
val model = MavenXpp3Reader().read(FileReader(pomFile))
val mavenProject = MavenProject(model)
mavenProject.setPomFile(pomFile)
mavenProject.collectedProjects = listOf() // no child modules
mavenProject.addCompileSourceRoot(mavenProject.build.sourceDirectory)
FieldUtils.writeField(mavenProject, "basedir", projectBaseDir, true)
mavenProject
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package org.utbot.maven.plugin.extension

import org.apache.maven.plugin.testing.AbstractMojoTestCase
import org.apache.maven.project.MavenProject
import org.junit.jupiter.api.*
import org.utbot.common.PathUtil.toPath
import org.utbot.engine.Mocker
import org.utbot.framework.codegen.*
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.MockFramework
import org.utbot.framework.plugin.api.MockStrategyApi
import org.utbot.maven.plugin.GenerateTestsAndSarifReportMojo
import org.utbot.maven.plugin.TestMavenProject
import java.io.File

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SarifMavenConfigurationProviderTest : AbstractMojoTestCase() {

@BeforeAll
override fun setUp() {
super.setUp()
}

@AfterAll
override fun tearDown() {
super.tearDown()
}

@Test
fun `targetClasses should be provided from the configuration`() {
Assertions.assertEquals(listOf("Main"), configurationProvider.targetClasses)
}

@Test
fun `projectRoot should be provided from the configuration`() {
Assertions.assertEquals(File("build/resources/project-to-test"), configurationProvider.projectRoot)
}

@Test
fun `generatedTestsRelativeRoot should be provided from the configuration`() {
Assertions.assertEquals("target/generated/test", configurationProvider.generatedTestsRelativeRoot)
}

@Test
fun `sarifReportsRelativeRoot should be provided from the configuration`() {
Assertions.assertEquals("target/generated/sarif", configurationProvider.sarifReportsRelativeRoot)
}

@Test
fun `markGeneratedTestsDirectoryAsTestSourcesRoot should be provided from the configuration`() {
Assertions.assertEquals(true, configurationProvider.markGeneratedTestsDirectoryAsTestSourcesRoot)
}

@Test
fun `testFramework should be provided from the configuration`() {
Assertions.assertEquals(Junit5, configurationProvider.testFramework)
}


@Test
fun `mockFramework should be provided from the configuration`() {
Assertions.assertEquals(MockFramework.MOCKITO, configurationProvider.mockFramework)
}


@Test
fun `generationTimeout should be provided from the configuration`() {
Assertions.assertEquals(10000, configurationProvider.generationTimeout)
}

@Test
fun `codegenLanguage should be provided from the configuration`() {
Assertions.assertEquals(CodegenLanguage.JAVA, configurationProvider.codegenLanguage)
}

@Test
fun `mockStrategy should be provided from the configuration`() {
Assertions.assertEquals(MockStrategyApi.OTHER_PACKAGES, configurationProvider.mockStrategy)
}

@Test
fun `staticsMocking should be provided from the configuration`() {
Assertions.assertEquals(MockitoStaticMocking, configurationProvider.staticsMocking)
}

@Test
fun `forceStaticMocking should be provided from the configuration`() {
Assertions.assertEquals(ForceStaticMocking.FORCE, configurationProvider.forceStaticMocking)
}

@Test
fun `classesToMockAlways should be provided from the configuration`() {
val expectedClassesToMockAlways =
(Mocker.defaultSuperClassesToMockAlwaysNames + "java.io.File").map(::ClassId).toSet()
Assertions.assertEquals(expectedClassesToMockAlways, configurationProvider.classesToMockAlways)
}

// internal

private val testMavenProject: TestMavenProject =
TestMavenProject("src/test/resources/project-to-test".toPath())

private val sarifReportMojo by lazy {
configureSarifReportMojo(testMavenProject.mavenProject)
}

private val configurationProvider by lazy {
sarifReportMojo.sarifProperties
}

private fun configureSarifReportMojo(mavenProject: MavenProject): GenerateTestsAndSarifReportMojo {
val generateTestsAndSarifReportMojo = configureMojo(
GenerateTestsAndSarifReportMojo(), "utbot-maven", mavenProject.file
) as GenerateTestsAndSarifReportMojo
generateTestsAndSarifReportMojo.mavenProject = mavenProject
return generateTestsAndSarifReportMojo
}
}
Loading