From 48523ac8ba5ab09c257f69fe462da88840dfc455 Mon Sep 17 00:00:00 2001 From: Arseniy Volynets Date: Mon, 8 Aug 2022 18:37:46 +0300 Subject: [PATCH 1/4] Backup sarif report --- .../client/handlers/TestsStreamHandler.kt | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt index 411e68ef..3b9a149e 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt @@ -1,27 +1,32 @@ package org.utbot.cpp.clion.plugin.client.handlers import com.intellij.openapi.project.Project +import com.intellij.util.io.exists import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import org.utbot.cpp.clion.plugin.utils.convertFromRemotePathIfNeeded import org.utbot.cpp.clion.plugin.utils.createFileWithText +import org.utbot.cpp.clion.plugin.utils.isSarifReport import org.utbot.cpp.clion.plugin.utils.logger import org.utbot.cpp.clion.plugin.utils.refreshAndFindNioFile import testsgen.Testgen import testsgen.Util +import java.nio.file.Files import java.nio.file.Path +import java.nio.file.Paths +import java.time.ZoneId class TestsStreamHandler( project: Project, grpcStream: Flow, progressName: String, cancellationJob: Job, - private val onSuccess: (List)->Unit = {}, - private val onError: (Throwable)->Unit = {} -): StreamHandlerWithProgress(project, grpcStream, progressName, cancellationJob) { + private val onSuccess: (List) -> Unit = {}, + private val onError: (Throwable) -> Unit = {} +) : StreamHandlerWithProgress(project, grpcStream, progressName, cancellationJob) { private val myGeneratedTestFilesLocalFS: MutableList = mutableListOf() - override fun onData(data: Testgen.TestsResponse) { + override suspend fun onData(data: Testgen.TestsResponse) { super.onData(data) handleSourceCode(data.testSourcesList) if (data.hasStubs()) { @@ -37,7 +42,7 @@ class TestsStreamHandler( sources.forEach { sourceCode -> val filePath: Path = sourceCode.filePath.convertFromRemotePathIfNeeded(project) - if (!isStubs) + if (!isStubs && !isSarifReport(filePath)) myGeneratedTestFilesLocalFS.add(filePath) if (sourceCode.code.isNotEmpty()) { @@ -58,6 +63,28 @@ class TestsStreamHandler( } } + fun backupPreviousClientSarifReport(localPath: String) { + fun Number.pad2(): String { + return ("0$this").takeLast(2) + } + + val oldPath = Paths.get(localPath) + if (oldPath.exists()) { + val ctime = Files.getLastModifiedTime(oldPath) + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime() + val newName = "project_code_analysis-" + + ctime.year.toString() + + (ctime.monthValue + 1).pad2() + + ctime.dayOfMonth.pad2() + + ctime.hour.pad2() + + ctime.minute.pad2() + ctime.second.pad2() + ".sarif"; + val newPath = Paths.get(oldPath.parent.toString(), newName) + Files.move(oldPath, newPath) + } + } + private fun isGeneratedFileTestSourceFile(fileName: String) = fileName.endsWith("_test.cpp") override fun onCompletion(exception: Throwable?) { From 2c4b38c79ee1e6b00a72d06884a633a1dbc837b6 Mon Sep 17 00:00:00 2001 From: Arseniy Volynets Date: Tue, 9 Aug 2022 02:06:20 +0300 Subject: [PATCH 2/4] backup sarif report --- .../handlers/ProjectConfigurationHandler.kt | 6 +- .../plugin/client/handlers/SourceCode.kt | 22 +++++ .../client/handlers/TestsStreamHandler.kt | 81 +++++++++++-------- .../client/requests/test/BaseTestsRequest.kt | 2 +- .../plugin/ui/services/TestsResultsStorage.kt | 28 ++----- .../utbot/cpp/clion/plugin/utils/FileUtils.kt | 6 +- .../utbot/cpp/clion/plugin/utils/PathUtils.kt | 1 + 7 files changed, 85 insertions(+), 61 deletions(-) create mode 100644 clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/SourceCode.kt diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt index b676d3f0..2e7f671f 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt @@ -15,7 +15,7 @@ import org.utbot.cpp.clion.plugin.utils.notifyError import org.utbot.cpp.clion.plugin.utils.notifyInfo import org.utbot.cpp.clion.plugin.utils.notifyUnknownResponse import org.utbot.cpp.clion.plugin.utils.notifyWarning -import org.utbot.cpp.clion.plugin.utils.refreshAndFindNioFile +import org.utbot.cpp.clion.plugin.utils.markDirtyAndRefresh import testsgen.Testgen abstract class ProjectConfigResponseHandler( @@ -98,7 +98,7 @@ class CreateBuildDirHandler( } else -> notifyUnknownResponse(response, project) } - refreshAndFindNioFile(project.settings.buildDirPath) + markDirtyAndRefresh(project.settings.buildDirPath) } } @@ -117,6 +117,6 @@ class GenerateJsonHandler( ) else -> notifyUnknownResponse(response, project) } - refreshAndFindNioFile(project.settings.buildDirPath) + markDirtyAndRefresh(project.settings.buildDirPath) } } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/SourceCode.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/SourceCode.kt new file mode 100644 index 00000000..b7c600be --- /dev/null +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/SourceCode.kt @@ -0,0 +1,22 @@ +package org.utbot.cpp.clion.plugin.client.handlers + +import com.intellij.openapi.project.Project +import org.utbot.cpp.clion.plugin.utils.convertFromRemotePathIfNeeded +import testsgen.Util +import java.nio.file.Path + +class SourceCode private constructor( + val localPath: Path, + val remotePath: String, + val content: String, + val regressionMethodsNumber: Int, + val errorMethodsNumber: Int +) { + constructor(serverSourceCode: Util.SourceCode, project: Project) : this( + serverSourceCode.filePath.convertFromRemotePathIfNeeded(project), + serverSourceCode.filePath, + serverSourceCode.code, + serverSourceCode.regressionMethodsNumber, + serverSourceCode.errorMethodsNumber + ) +} diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt index 3b9a149e..ebda3e23 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt @@ -1,14 +1,17 @@ package org.utbot.cpp.clion.plugin.client.handlers +import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.util.io.exists import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow -import org.utbot.cpp.clion.plugin.utils.convertFromRemotePathIfNeeded +import org.utbot.cpp.clion.plugin.settings.settings +import org.utbot.cpp.clion.plugin.ui.services.TestsResultsStorage import org.utbot.cpp.clion.plugin.utils.createFileWithText import org.utbot.cpp.clion.plugin.utils.isSarifReport import org.utbot.cpp.clion.plugin.utils.logger -import org.utbot.cpp.clion.plugin.utils.refreshAndFindNioFile +import org.utbot.cpp.clion.plugin.utils.markDirtyAndRefresh +import org.utbot.cpp.clion.plugin.utils.nioPath import testsgen.Testgen import testsgen.Util import java.nio.file.Files @@ -25,50 +28,64 @@ class TestsStreamHandler( private val onError: (Throwable) -> Unit = {} ) : StreamHandlerWithProgress(project, grpcStream, progressName, cancellationJob) { private val myGeneratedTestFilesLocalFS: MutableList = mutableListOf() - - override suspend fun onData(data: Testgen.TestsResponse) { + override fun onData(data: Testgen.TestsResponse) { super.onData(data) - handleSourceCode(data.testSourcesList) - if (data.hasStubs()) { - handleSourceCode(data.stubs.stubSourcesList, true) + val (testSourceCodes, sarifSourceCodes) = data.testSourcesList.map { SourceCode(it, project) }.partition { + !it.localPath.isSarifReport() } - } + val stubSourceCodes = data.stubs.stubSourcesList.map { SourceCode(it, project) } - override fun Testgen.TestsResponse.getProgress(): Util.Progress { - return progress - } + project.service().newTestsGenerated(testSourceCodes) + + sarifSourceCodes.forEach { + backupPreviousClientSarifReport(it.localPath) + } - private fun handleSourceCode(sources: List, isStubs: Boolean = false) { - sources.forEach { sourceCode -> - val filePath: Path = sourceCode.filePath.convertFromRemotePathIfNeeded(project) + // if local scenario: server already created files + if (project.settings.isRemoteScenario) { + writeSourceCodes(testSourceCodes, "test") + writeSourceCodes(sarifSourceCodes, "sarif report") + writeSourceCodes(stubSourceCodes, "stub") + } - if (!isStubs && !isSarifReport(filePath)) - myGeneratedTestFilesLocalFS.add(filePath) + // prepare list of generated test files for further processing + myGeneratedTestFilesLocalFS.addAll(testSourceCodes.map { it.localPath }) - if (sourceCode.code.isNotEmpty()) { - project.logger.trace { "Creating generated test file: $filePath." } - createFileWithText( - filePath, - sourceCode.code - ) - } + // log to user + testSourceCodes.forEach { sourceCode -> + val isTestFileSourceFile = sourceCode.localPath.endsWith("_test.cpp") + if (isTestFileSourceFile) + project.logger.info { + "Generated test with ${sourceCode.regressionMethodsNumber} tests in regression suite" + + " and ${sourceCode.errorMethodsNumber} tests in error suite" + } + else + project.logger.info { "Generated test file ${sourceCode.localPath}" } + } + sarifSourceCodes.forEach { + project.logger.info { "Generated SARIF file ${it.localPath}" } + } - var infoMessage = "Generated " + if (isStubs) "stub" else "test" + " file" - if (isGeneratedFileTestSourceFile(filePath.toString())) - infoMessage += " with ${sourceCode.regressionMethodsNumber} tests in regression suite" + - " and ${sourceCode.errorMethodsNumber} tests in error suite" - project.logger.info { "$infoMessage: $filePath" } + // tell ide to refresh vfs and refresh project tree + markDirtyAndRefresh(project.nioPath) + } - refreshAndFindNioFile(filePath) + private fun writeSourceCodes(sourceCodes: List, fileKind: String) { + sourceCodes.forEach { + project.logger.info { "Write $fileKind file ${it.remotePath} to ${it.localPath}" } + createFileWithText(it.localPath, it.content) } } - fun backupPreviousClientSarifReport(localPath: String) { + override fun Testgen.TestsResponse.getProgress(): Util.Progress { + return progress + } + + private fun backupPreviousClientSarifReport(oldPath: Path) { fun Number.pad2(): String { return ("0$this").takeLast(2) } - val oldPath = Paths.get(localPath) if (oldPath.exists()) { val ctime = Files.getLastModifiedTime(oldPath) .toInstant() @@ -85,8 +102,6 @@ class TestsStreamHandler( } } - private fun isGeneratedFileTestSourceFile(fileName: String) = fileName.endsWith("_test.cpp") - override fun onCompletion(exception: Throwable?) { super.onCompletion(exception) if (exception == null) diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt index 4d11e570..c11e159c 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt @@ -36,7 +36,7 @@ abstract class BaseTestsRequest(request: R, project: Project, private val pro } open fun getFocusTarget(generatedTestFiles: List): Path? { - return generatedTestFiles.filter { !isHeaderFile(it) && !isSarifReport(it) }.getLongestCommonPathFromRoot() + return generatedTestFiles.filter { !isHeaderFile(it) && !it.isSarifReport() }.getLongestCommonPathFromRoot() } override fun logRequest() { diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt index aa9fc3dc..a1d011a2 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.newvfs.BulkFileListener import com.intellij.openapi.vfs.newvfs.events.VFileEvent +import org.utbot.cpp.clion.plugin.client.handlers.SourceCode import org.utbot.cpp.clion.plugin.listeners.UTBotTestResultsReceivedListener import org.utbot.cpp.clion.plugin.utils.convertFromRemotePathIfNeeded import testsgen.Testgen @@ -31,31 +32,16 @@ class TestsResultsStorage(val project: Project) { forceGutterIconsUpdate() }) - - connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener { - override fun after(events: MutableList) { - var wasSave = false - events.forEach { event -> - if (event.isFromSave) { - wasSave = true - storage.forEach { entry -> - if (entry.value.testFilePath != event.path) { - storage.remove(entry.key) - } - } - } - } - - if (wasSave) { - forceGutterIconsUpdate() - } - } - }) - } fun getTestResultByTestName(testName: String): Testgen.TestResultObject? = storage[testName] + fun newTestsGenerated(sourceCodes: List) { + // for tests that were regenerated forget results from previous test run + val localFilePaths = sourceCodes.map { it.localPath }.toSet() + storage.values.removeIf { it.testFilePath.convertFromRemotePathIfNeeded(project) in localFilePaths } + } + private fun shouldForceUpdate(): Boolean { val currentlyOpenedFilePaths = FileEditorManager.getInstance(project) .selectedEditors diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt index ed4e64ca..331c5fb1 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt @@ -6,7 +6,7 @@ import com.intellij.util.io.exists import kotlin.io.path.writeText import java.nio.file.Path -fun refreshAndFindNioFile(path: Path, async: Boolean = true, recursive: Boolean = true, reloadChildren: Boolean = true) { +fun markDirtyAndRefresh(path: Path, async: Boolean = true, recursive: Boolean = true, reloadChildren: Boolean = true) { VfsUtil.markDirtyAndRefresh(async, recursive, reloadChildren, path.toFile()) } @@ -25,6 +25,6 @@ fun isCPPFileName(fileName: String) = """.*\.(cpp|hpp|h)""".toRegex().matches(fi fun isHeaderFile(fileName: String) = """.*\.([ch])""".toRegex().matches(fileName) fun isHeaderFile(path: Path) = isHeaderFile(path.fileName.toString()) -fun isSarifReport(fileName: String) = fileName.endsWith(".sarif") +fun String.isSarifReport() = this.endsWith(".sarif") -fun isSarifReport(path: Path) = isSarifReport(path.fileName.toString()) +fun Path.isSarifReport() = this.fileName.toString().isSarifReport() diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt index f5ff421f..efdc8fa7 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt @@ -15,6 +15,7 @@ import java.util.* import kotlin.io.path.div val Project.path get() = this.basePath ?: error("Project path can't be null!") +val Project.nioPath: Path get() = Paths.get(this.path) fun relativize(from: String, to: String): String { val toPath = Paths.get(to) From f544f4ad3dd04a2c2bc5298e362dbd51b67d9eae Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Wed, 10 Aug 2022 15:20:07 +0300 Subject: [PATCH 3/4] Little code improvements --- .../client/handlers/TestsStreamHandler.kt | 65 ++++++++++--------- .../client/requests/test/BaseTestsRequest.kt | 11 ++-- .../plugin/ui/services/TestsResultsStorage.kt | 9 ++- .../utbot/cpp/clion/plugin/utils/FileUtils.kt | 13 ++-- .../utbot/cpp/clion/plugin/utils/PathUtils.kt | 2 + 5 files changed, 51 insertions(+), 49 deletions(-) diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt index ebda3e23..55f466e3 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt @@ -27,78 +27,83 @@ class TestsStreamHandler( private val onSuccess: (List) -> Unit = {}, private val onError: (Throwable) -> Unit = {} ) : StreamHandlerWithProgress(project, grpcStream, progressName, cancellationJob) { + private val myGeneratedTestFilesLocalFS: MutableList = mutableListOf() + override fun onData(data: Testgen.TestsResponse) { super.onData(data) - val (testSourceCodes, sarifSourceCodes) = data.testSourcesList.map { SourceCode(it, project) }.partition { - !it.localPath.isSarifReport() - } + + val (testSourceCodes, sarifSourceCodes) = data.testSourcesList + .map { SourceCode(it, project) } + .partition { !it.localPath.isSarifReport() } val stubSourceCodes = data.stubs.stubSourcesList.map { SourceCode(it, project) } - project.service().newTestsGenerated(testSourceCodes) + project.service().clearTestResults(testSourceCodes) + //Q: why several sarif source codes? don't we obtain one merged sarif report from server? sarifSourceCodes.forEach { backupPreviousClientSarifReport(it.localPath) } // if local scenario: server already created files if (project.settings.isRemoteScenario) { - writeSourceCodes(testSourceCodes, "test") - writeSourceCodes(sarifSourceCodes, "sarif report") - writeSourceCodes(stubSourceCodes, "stub") + createSourceCodeFiles(testSourceCodes, "test") + createSourceCodeFiles(sarifSourceCodes, "sarif report") + createSourceCodeFiles(stubSourceCodes, "stub") } // prepare list of generated test files for further processing myGeneratedTestFilesLocalFS.addAll(testSourceCodes.map { it.localPath }) // log to user + //Q: I do not understand this logic, what is the scenarios here? testSourceCodes.forEach { sourceCode -> - val isTestFileSourceFile = sourceCode.localPath.endsWith("_test.cpp") - if (isTestFileSourceFile) - project.logger.info { - "Generated test with ${sourceCode.regressionMethodsNumber} tests in regression suite" + - " and ${sourceCode.errorMethodsNumber} tests in error suite" - } - else - project.logger.info { "Generated test file ${sourceCode.localPath}" } + val isTestSourceFile = sourceCode.localPath.endsWith("_test.cpp") + val testsGenerationResultMessage = if (isTestSourceFile) { + "Generated ${sourceCode.regressionMethodsNumber} tests in regression suite" + + " and ${sourceCode.errorMethodsNumber} tests in error suite" + } else { + "Generated test file ${sourceCode.localPath}" + } + logger.info(testsGenerationResultMessage) } + sarifSourceCodes.forEach { - project.logger.info { "Generated SARIF file ${it.localPath}" } + project.logger.info { "Generated SARIF report file ${it.localPath}" } } // tell ide to refresh vfs and refresh project tree markDirtyAndRefresh(project.nioPath) } - private fun writeSourceCodes(sourceCodes: List, fileKind: String) { + private fun createSourceCodeFiles(sourceCodes: List, fileKind: String) { sourceCodes.forEach { project.logger.info { "Write $fileKind file ${it.remotePath} to ${it.localPath}" } createFileWithText(it.localPath, it.content) } } - override fun Testgen.TestsResponse.getProgress(): Util.Progress { - return progress - } + override fun Testgen.TestsResponse.getProgress(): Util.Progress = progress - private fun backupPreviousClientSarifReport(oldPath: Path) { - fun Number.pad2(): String { - return ("0$this").takeLast(2) - } + private fun backupPreviousClientSarifReport(previousReportPaths: Path) { + fun Number.pad2(): String = ("0$this").takeLast(2) - if (oldPath.exists()) { - val ctime = Files.getLastModifiedTime(oldPath) + if (previousReportPaths.exists()) { + val ctime = Files.getLastModifiedTime(previousReportPaths) .toInstant() .atZone(ZoneId.systemDefault()) .toLocalDateTime() - val newName = "project_code_analysis-" + + + val newReportName = "project_code_analysis-" + ctime.year.toString() + (ctime.monthValue + 1).pad2() + ctime.dayOfMonth.pad2() + ctime.hour.pad2() + - ctime.minute.pad2() + ctime.second.pad2() + ".sarif"; - val newPath = Paths.get(oldPath.parent.toString(), newName) - Files.move(oldPath, newPath) + ctime.minute.pad2() + + ctime.second.pad2() + + ".sarif" + val newPath = Paths.get(previousReportPaths.parent.toString(), newReportName) + Files.move(previousReportPaths, newPath) } } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt index c11e159c..8ecde326 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/requests/test/BaseTestsRequest.kt @@ -35,13 +35,10 @@ abstract class BaseTestsRequest(request: R, project: Project, private val pro } } - open fun getFocusTarget(generatedTestFiles: List): Path? { - return generatedTestFiles.filter { !isHeaderFile(it) && !it.isSarifReport() }.getLongestCommonPathFromRoot() - } - - override fun logRequest() { - logger.info { "$logMessage \n$request" } - } + open fun getFocusTarget(generatedTestFiles: List): Path? = + generatedTestFiles + .filter { !isHeaderFile(it) && !it.isSarifReport() } + .getLongestCommonPathFromRoot() open fun getInfoMessage() = "Tests generated!" diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt index a1d011a2..e35bebd5 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/services/TestsResultsStorage.kt @@ -5,9 +5,6 @@ import com.intellij.openapi.components.Service import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.openapi.vfs.newvfs.BulkFileListener -import com.intellij.openapi.vfs.newvfs.events.VFileEvent import org.utbot.cpp.clion.plugin.client.handlers.SourceCode import org.utbot.cpp.clion.plugin.listeners.UTBotTestResultsReceivedListener import org.utbot.cpp.clion.plugin.utils.convertFromRemotePathIfNeeded @@ -36,8 +33,10 @@ class TestsResultsStorage(val project: Project) { fun getTestResultByTestName(testName: String): Testgen.TestResultObject? = storage[testName] - fun newTestsGenerated(sourceCodes: List) { - // for tests that were regenerated forget results from previous test run + /** + * Cleans the results of previous test run if tests were regenerated. + */ + fun clearTestResults(sourceCodes: List) { val localFilePaths = sourceCodes.map { it.localPath }.toSet() storage.values.removeIf { it.testFilePath.convertFromRemotePathIfNeeded(project) in localFilePaths } } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt index 331c5fb1..58ffb235 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt @@ -6,9 +6,12 @@ import com.intellij.util.io.exists import kotlin.io.path.writeText import java.nio.file.Path -fun markDirtyAndRefresh(path: Path, async: Boolean = true, recursive: Boolean = true, reloadChildren: Boolean = true) { - VfsUtil.markDirtyAndRefresh(async, recursive, reloadChildren, path.toFile()) -} +fun markDirtyAndRefresh( + path: Path, + async: Boolean = true, + recursive: Boolean = true, + reloadChildren: Boolean = true, +) = VfsUtil.markDirtyAndRefresh(async, recursive, reloadChildren, path.toFile()) fun createFileWithText(filePath: Path, text: String) { with(filePath) { @@ -24,7 +27,3 @@ fun isCPPFileName(fileName: String) = """.*\.(cpp|hpp|h)""".toRegex().matches(fi fun isHeaderFile(fileName: String) = """.*\.([ch])""".toRegex().matches(fileName) fun isHeaderFile(path: Path) = isHeaderFile(path.fileName.toString()) - -fun String.isSarifReport() = this.endsWith(".sarif") - -fun Path.isSarifReport() = this.fileName.toString().isSarifReport() diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt index efdc8fa7..c469a7ed 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/PathUtils.kt @@ -52,6 +52,8 @@ fun Path.visitAllDirectories(action: (Path) -> Unit) { } } +fun Path.isSarifReport() = this.fileName.toString().endsWith(".sarif") + fun String.fileNameOrNull(): String? { return try { Paths.get(this).fileName.toString() From 663096244b3eabe481e1ef3e818bb6ee8d1c86ff Mon Sep 17 00:00:00 2001 From: Arseniy Volynets Date: Thu, 11 Aug 2022 10:43:12 +0300 Subject: [PATCH 4/4] handle one sarif report --- .../client/handlers/TestsStreamHandler.kt | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt index 55f466e3..f889bb0f 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/TestsStreamHandler.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.ui.services.TestsResultsStorage +import org.utbot.cpp.clion.plugin.utils.convertFromRemotePathIfNeeded import org.utbot.cpp.clion.plugin.utils.createFileWithText import org.utbot.cpp.clion.plugin.utils.isSarifReport import org.utbot.cpp.clion.plugin.utils.logger @@ -33,47 +34,58 @@ class TestsStreamHandler( override fun onData(data: Testgen.TestsResponse) { super.onData(data) - val (testSourceCodes, sarifSourceCodes) = data.testSourcesList + val testSourceCodes = data.testSourcesList .map { SourceCode(it, project) } - .partition { !it.localPath.isSarifReport() } + .filter { !it.localPath.isSarifReport() } + handleTestSources(testSourceCodes) + val stubSourceCodes = data.stubs.stubSourcesList.map { SourceCode(it, project) } + handleStubSources(stubSourceCodes) + + val sarifReport = + data.testSourcesList.find { it.filePath.convertFromRemotePathIfNeeded(project).isSarifReport() }?.let { + SourceCode(it, project) + } + sarifReport?.let { handleSarifReport(it) } + // for new generated tests remove previous testResults project.service().clearTestResults(testSourceCodes) - //Q: why several sarif source codes? don't we obtain one merged sarif report from server? - sarifSourceCodes.forEach { - backupPreviousClientSarifReport(it.localPath) - } + // tell ide to refresh vfs and refresh project tree + markDirtyAndRefresh(project.nioPath) + } - // if local scenario: server already created files + private fun handleSarifReport(sarif: SourceCode) { + backupPreviousClientSarifReport(sarif.localPath) + createSourceCodeFiles(listOf(sarif), "sarif report") + project.logger.info { "Generated SARIF report file ${sarif.localPath}" } + } + + private fun handleTestSources(sources: List) { if (project.settings.isRemoteScenario) { - createSourceCodeFiles(testSourceCodes, "test") - createSourceCodeFiles(sarifSourceCodes, "sarif report") - createSourceCodeFiles(stubSourceCodes, "stub") + createSourceCodeFiles(sources, "test") } // prepare list of generated test files for further processing - myGeneratedTestFilesLocalFS.addAll(testSourceCodes.map { it.localPath }) + myGeneratedTestFilesLocalFS.addAll(sources.map { it.localPath }) - // log to user - //Q: I do not understand this logic, what is the scenarios here? - testSourceCodes.forEach { sourceCode -> + sources.forEach { sourceCode -> val isTestSourceFile = sourceCode.localPath.endsWith("_test.cpp") val testsGenerationResultMessage = if (isTestSourceFile) { "Generated ${sourceCode.regressionMethodsNumber} tests in regression suite" + " and ${sourceCode.errorMethodsNumber} tests in error suite" } else { + // .h file "Generated test file ${sourceCode.localPath}" } logger.info(testsGenerationResultMessage) } + } - sarifSourceCodes.forEach { - project.logger.info { "Generated SARIF report file ${it.localPath}" } + private fun handleStubSources(sources: List) { + if (project.settings.isRemoteScenario) { + createSourceCodeFiles(sources, "stub") } - - // tell ide to refresh vfs and refresh project tree - markDirtyAndRefresh(project.nioPath) } private fun createSourceCodeFiles(sourceCodes: List, fileKind: String) {