diff --git a/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsCommand.kt b/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsCommand.kt index 35d69dcd8a..b0b7101011 100644 --- a/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsCommand.kt +++ b/utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsCommand.kt @@ -149,7 +149,7 @@ class GenerateTestsCommand : else -> { val sourceFinding = SourceFindingStrategyDefault(classFqn, sourceCodeFile, testsFilePath, projectRootPath) - val report = SarifReport(testSets, testClassBody, sourceFinding).createReport() + val report = SarifReport(testSets, testClassBody, sourceFinding).createReport().toJson() saveToFile(report, sarifReport) println("The report was saved to \"$sarifReport\".") } diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/sarif/SarifReportTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/sarif/SarifReportTest.kt index 888d02a816..44aa51e5f3 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/sarif/SarifReportTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/sarif/SarifReportTest.kt @@ -1,7 +1,5 @@ package org.utbot.sarif -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue import org.junit.Test import org.mockito.Mockito import org.utbot.framework.plugin.api.ExecutableId @@ -19,7 +17,7 @@ class SarifReportTest { testSets = listOf(), generatedTestsCode = "", sourceFindingEmpty - ).createReport() + ).createReport().toJson() assert(actualReport.isNotEmpty()) } @@ -30,7 +28,7 @@ class SarifReportTest { testSets = listOf(testSet), generatedTestsCode = "", sourceFindingEmpty - ).createReport().toSarif() + ).createReport() assert(sarif.runs.first().results.isEmpty()) } @@ -60,7 +58,7 @@ class SarifReportTest { testSets = testSets, generatedTestsCode = "", sourceFindingEmpty - ).createReport().toSarif() + ).createReport() assert(report.runs.first().results[0].message.text.contains("NullPointerException")) assert(report.runs.first().results[1].message.text.contains("ArrayIndexOutOfBoundsException")) @@ -77,7 +75,7 @@ class SarifReportTest { Mockito.`when`(mockUtExecution.path.lastOrNull()?.stmt?.javaSourceStartLineNumber).thenReturn(1337) Mockito.`when`(mockUtExecution.testMethodName).thenReturn("testMain_ThrowArithmeticException") - val report = sarifReportMain.createReport().toSarif() + val report = sarifReportMain.createReport() val result = report.runs.first().results.first() val location = result.locations.first().physicalLocation @@ -105,7 +103,7 @@ class SarifReportTest { ) ) - val report = sarifReportMain.createReport().toSarif() + val report = sarifReportMain.createReport() val result = report.runs.first().results.first() assert(result.message.text.contains("227")) @@ -128,7 +126,7 @@ class SarifReportTest { ) Mockito.`when`(mockUtExecution.stateBefore.parameters).thenReturn(listOf()) - val report = sarifReportMain.createReport().toSarif() + val report = sarifReportMain.createReport() val result = report.runs.first().results.first().codeFlows.first().threadFlows.first().locations.map { it.location.physicalLocation @@ -153,7 +151,7 @@ class SarifReportTest { Mockito.`when`(mockUtExecution.stateBefore.parameters).thenReturn(listOf()) Mockito.`when`(mockUtExecution.testMethodName).thenReturn("testMain_ThrowArithmeticException") - val report = sarifReportMain.createReport().toSarif() + val report = sarifReportMain.createReport() val codeFlowPhysicalLocations = report.runs[0].results[0].codeFlows[0].threadFlows[0].locations.map { it.location.physicalLocation @@ -177,7 +175,7 @@ class SarifReportTest { Mockito.`when`(mockUtExecution.stateBefore.parameters).thenReturn(listOf()) Mockito.`when`(mockUtExecution.testMethodName).thenReturn("testMain_ThrowArithmeticException") - val report = sarifReportPrivateMain.createReport().toSarif() + val report = sarifReportPrivateMain.createReport() val codeFlowPhysicalLocations = report.runs[0].results[0].codeFlows[0].threadFlows[0].locations.map { it.location.physicalLocation @@ -203,7 +201,7 @@ class SarifReportTest { testSets = testSets, generatedTestsCode = "", sourceFindingMain - ).createReport().toSarif() + ).createReport() assert(report.runs.first().results.size == 1) // no duplicates } @@ -228,7 +226,7 @@ class SarifReportTest { testSets = testSets, generatedTestsCode = "", sourceFindingMain - ).createReport().toSarif() + ).createReport() assert(report.runs.first().results.size == 2) // no results have been removed } @@ -257,7 +255,7 @@ class SarifReportTest { testSets = testSets, generatedTestsCode = "", sourceFindingMain - ).createReport().toSarif() + ).createReport() assert(report.runs.first().results.size == 2) // no results have been removed } @@ -291,7 +289,7 @@ class SarifReportTest { testSets = testSets, generatedTestsCode = "", sourceFindingMain - ).createReport().toSarif() + ).createReport() assert(report.runs.first().results.size == 1) // no duplicates assert(report.runs.first().results.first().totalCodeFlowLocations() == 1) // with a shorter stack trace @@ -310,8 +308,6 @@ class SarifReportTest { Mockito.`when`(mockExecutableId.classId.name).thenReturn("Main") } - private fun String.toSarif(): Sarif = jacksonObjectMapper().readValue(this) - // constants private val sourceFindingEmpty = SourceFindingStrategyDefault( diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt index 4c41010460..b0a2800086 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/plugin/sarif/GenerateTestsAndSarifReportFacade.kt @@ -91,7 +91,7 @@ class GenerateTestsAndSarifReportFacade( testClassBody: String, sourceFinding: SourceFindingStrategy ) { - val sarifReport = SarifReport(testSets, testClassBody, sourceFinding).createReport() + val sarifReport = SarifReport(testSets, testClassBody, sourceFinding).createReport().toJson() targetClass.sarifReportFile.writeText(sarifReport) } } \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineMain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineMain.kt index 37624646d6..f240015ed5 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineMain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineMain.kt @@ -182,7 +182,7 @@ private fun EngineProcessModel.setup( testSets[params.testSetsId]!!, params.generatedTestsCode, RdSourceFindingStrategyFacade(realProtocol.rdSourceFindingStrategy) - ).createReport() + ).createReport().toJson() ) } synchronizer.measureExecutionForTermination(generateTestReport) { params -> diff --git a/utbot-framework/src/main/kotlin/org/utbot/sarif/DataClasses.kt b/utbot-framework/src/main/kotlin/org/utbot/sarif/DataClasses.kt index 5ecae62040..1cc571f047 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/sarif/DataClasses.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/sarif/DataClasses.kt @@ -1,7 +1,10 @@ package org.utbot.sarif +import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonValue +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue /** * Useful links: @@ -24,7 +27,19 @@ data class Sarif( fun fromRun(run: SarifRun) = Sarif(defaultSchema, defaultVersion, listOf(run)) + + fun fromJson(reportInJson: String): Sarif = + jacksonObjectMapper().readValue(reportInJson) } + + fun toJson(): String = + jacksonObjectMapper() + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(this) + + fun getAllResults(): List = + runs.flatMap { it.results } } /** @@ -104,8 +119,8 @@ data class SarifResult( * Returns the total number of locations in all [codeFlows]. */ fun totalCodeFlowLocations() = - codeFlows.sumBy { codeFlow -> - codeFlow.threadFlows.sumBy { threadFlow -> + codeFlows.sumOf { codeFlow -> + codeFlow.threadFlows.sumOf { threadFlow -> threadFlow.locations.size } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/sarif/SarifReport.kt b/utbot-framework/src/main/kotlin/org/utbot/sarif/SarifReport.kt index 2166156bac..670e76e4f9 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/sarif/SarifReport.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/sarif/SarifReport.kt @@ -1,12 +1,10 @@ package org.utbot.sarif -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue import org.utbot.common.PathUtil.fileExtension import org.utbot.common.PathUtil.toPath import org.utbot.framework.UtSettings import org.utbot.framework.plugin.api.* +import kotlin.io.path.nameWithoutExtension /** * Used for the SARIF report creation by given test cases and generated tests code. @@ -21,45 +19,20 @@ class SarifReport( private val generatedTestsCode: String, private val sourceFinding: SourceFindingStrategy ) { - companion object { - /** * Merges several SARIF reports given as JSON-strings into one */ fun mergeReports(reports: List): String = reports.fold(Sarif.empty()) { sarif: Sarif, report: String -> - sarif.copy(runs = sarif.runs + report.jsonToSarif().runs) - }.sarifToJson() - - // internal - - private fun String.jsonToSarif(): Sarif = - jacksonObjectMapper().readValue(this) - - private fun Sarif.sarifToJson(): String = - jacksonObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .writerWithDefaultPrettyPrinter() - .writeValueAsString(this) + sarif.copy(runs = sarif.runs + Sarif.fromJson(report).runs) + }.toJson() } /** - * Creates a SARIF report and returns it as string - */ - fun createReport(): String = - constructSarif().sarifToJson() - - // internal - - private val defaultLineNumber = 1 // if the line in the source code where the exception is thrown is unknown - - /** - * [Read more about links to locations](https://github.com/microsoft/sarif-tutorials/blob/main/docs/3-Beyond-basics.md#msg-links-location) + * Creates a SARIF report. */ - private val relatedLocationId = 1 // for attaching link to generated test in related locations - - private fun constructSarif(): Sarif { + fun createReport(): Sarif { val sarifResults = mutableListOf() val sarifRules = mutableSetOf() @@ -85,6 +58,15 @@ class SarifReport( ) } + // internal + + private val defaultLineNumber = 1 // if the line in the source code where the exception is thrown is unknown + + /** + * [Read more about links to locations](https://github.com/microsoft/sarif-tutorials/blob/main/docs/3-Beyond-basics.md#msg-links-location) + */ + private val relatedLocationId = 1 // for attaching link to generated test in related locations + /** * Minimizes detected errors and removes duplicates. * @@ -227,10 +209,14 @@ class SarifReport( val methodCallLocation: SarifPhysicalLocation? = findMethodCallInTestBody(utExecution.testMethodName, method.name) if (methodCallLocation != null) { + val testFileName = sourceFinding.testsRelativePath.toPath().fileName + val testClassName = testFileName.nameWithoutExtension + val testMethodName = utExecution.testMethodName + val methodCallLineNumber = methodCallLocation.region.startLine val methodCallLocationWrapper = SarifFlowLocationWrapper( SarifFlowLocation( message = Message( - text = "${sourceFinding.testsRelativePath.toPath().fileName}:${methodCallLocation.region.startLine}" + text = "$testClassName.$testMethodName($testFileName:$methodCallLineNumber)" ), physicalLocation = methodCallLocation )