|
1 | 1 | package org.utbot.cpp.clion.plugin.client.handlers
|
2 | 2 |
|
| 3 | +import com.intellij.openapi.components.service |
3 | 4 | import com.intellij.openapi.project.Project
|
| 5 | +import com.intellij.util.io.exists |
4 | 6 | import kotlinx.coroutines.Job
|
5 | 7 | import kotlinx.coroutines.flow.Flow
|
| 8 | +import org.utbot.cpp.clion.plugin.settings.settings |
| 9 | +import org.utbot.cpp.clion.plugin.ui.services.TestsResultsStorage |
6 | 10 | import org.utbot.cpp.clion.plugin.utils.convertFromRemotePathIfNeeded
|
7 | 11 | import org.utbot.cpp.clion.plugin.utils.createFileWithText
|
| 12 | +import org.utbot.cpp.clion.plugin.utils.isSarifReport |
8 | 13 | import org.utbot.cpp.clion.plugin.utils.logger
|
9 |
| -import org.utbot.cpp.clion.plugin.utils.refreshAndFindNioFile |
| 14 | +import org.utbot.cpp.clion.plugin.utils.markDirtyAndRefresh |
| 15 | +import org.utbot.cpp.clion.plugin.utils.nioPath |
10 | 16 | import testsgen.Testgen
|
11 | 17 | import testsgen.Util
|
| 18 | +import java.nio.file.Files |
12 | 19 | import java.nio.file.Path
|
| 20 | +import java.nio.file.Paths |
| 21 | +import java.time.ZoneId |
13 | 22 |
|
14 | 23 | class TestsStreamHandler(
|
15 | 24 | project: Project,
|
16 | 25 | grpcStream: Flow<Testgen.TestsResponse>,
|
17 | 26 | progressName: String,
|
18 | 27 | cancellationJob: Job,
|
19 |
| - private val onSuccess: (List<Path>)->Unit = {}, |
20 |
| - private val onError: (Throwable)->Unit = {} |
21 |
| -): StreamHandlerWithProgress<Testgen.TestsResponse>(project, grpcStream, progressName, cancellationJob) { |
| 28 | + private val onSuccess: (List<Path>) -> Unit = {}, |
| 29 | + private val onError: (Throwable) -> Unit = {} |
| 30 | +) : StreamHandlerWithProgress<Testgen.TestsResponse>(project, grpcStream, progressName, cancellationJob) { |
| 31 | + |
22 | 32 | private val myGeneratedTestFilesLocalFS: MutableList<Path> = mutableListOf()
|
23 | 33 |
|
24 | 34 | override fun onData(data: Testgen.TestsResponse) {
|
25 | 35 | super.onData(data)
|
26 |
| - handleSourceCode(data.testSourcesList) |
27 |
| - if (data.hasStubs()) { |
28 |
| - handleSourceCode(data.stubs.stubSourcesList, true) |
29 |
| - } |
| 36 | + |
| 37 | + val testSourceCodes = data.testSourcesList |
| 38 | + .map { SourceCode(it, project) } |
| 39 | + .filter { !it.localPath.isSarifReport() } |
| 40 | + handleTestSources(testSourceCodes) |
| 41 | + |
| 42 | + val stubSourceCodes = data.stubs.stubSourcesList.map { SourceCode(it, project) } |
| 43 | + handleStubSources(stubSourceCodes) |
| 44 | + |
| 45 | + val sarifReport = |
| 46 | + data.testSourcesList.find { it.filePath.convertFromRemotePathIfNeeded(project).isSarifReport() }?.let { |
| 47 | + SourceCode(it, project) |
| 48 | + } |
| 49 | + sarifReport?.let { handleSarifReport(it) } |
| 50 | + |
| 51 | + // for new generated tests remove previous testResults |
| 52 | + project.service<TestsResultsStorage>().clearTestResults(testSourceCodes) |
| 53 | + |
| 54 | + // tell ide to refresh vfs and refresh project tree |
| 55 | + markDirtyAndRefresh(project.nioPath) |
30 | 56 | }
|
31 | 57 |
|
32 |
| - override fun Testgen.TestsResponse.getProgress(): Util.Progress { |
33 |
| - return progress |
| 58 | + private fun handleSarifReport(sarif: SourceCode) { |
| 59 | + backupPreviousClientSarifReport(sarif.localPath) |
| 60 | + createSourceCodeFiles(listOf(sarif), "sarif report") |
| 61 | + project.logger.info { "Generated SARIF report file ${sarif.localPath}" } |
34 | 62 | }
|
35 | 63 |
|
36 |
| - private fun handleSourceCode(sources: List<Util.SourceCode>, isStubs: Boolean = false) { |
37 |
| - sources.forEach { sourceCode -> |
38 |
| - val filePath: Path = sourceCode.filePath.convertFromRemotePathIfNeeded(project) |
| 64 | + private fun handleTestSources(sources: List<SourceCode>) { |
| 65 | + if (project.settings.isRemoteScenario) { |
| 66 | + createSourceCodeFiles(sources, "test") |
| 67 | + } |
39 | 68 |
|
40 |
| - if (!isStubs) |
41 |
| - myGeneratedTestFilesLocalFS.add(filePath) |
| 69 | + // prepare list of generated test files for further processing |
| 70 | + myGeneratedTestFilesLocalFS.addAll(sources.map { it.localPath }) |
42 | 71 |
|
43 |
| - if (sourceCode.code.isNotEmpty()) { |
44 |
| - project.logger.trace { "Creating generated test file: $filePath." } |
45 |
| - createFileWithText( |
46 |
| - filePath, |
47 |
| - sourceCode.code |
48 |
| - ) |
| 72 | + sources.forEach { sourceCode -> |
| 73 | + val isTestSourceFile = sourceCode.localPath.endsWith("_test.cpp") |
| 74 | + val testsGenerationResultMessage = if (isTestSourceFile) { |
| 75 | + "Generated ${sourceCode.regressionMethodsNumber} tests in regression suite" + |
| 76 | + " and ${sourceCode.errorMethodsNumber} tests in error suite" |
| 77 | + } else { |
| 78 | + // .h file |
| 79 | + "Generated test file ${sourceCode.localPath}" |
49 | 80 | }
|
| 81 | + logger.info(testsGenerationResultMessage) |
| 82 | + } |
| 83 | + } |
50 | 84 |
|
51 |
| - var infoMessage = "Generated " + if (isStubs) "stub" else "test" + " file" |
52 |
| - if (isGeneratedFileTestSourceFile(filePath.toString())) |
53 |
| - infoMessage += " with ${sourceCode.regressionMethodsNumber} tests in regression suite" + |
54 |
| - " and ${sourceCode.errorMethodsNumber} tests in error suite" |
55 |
| - project.logger.info { "$infoMessage: $filePath" } |
| 85 | + private fun handleStubSources(sources: List<SourceCode>) { |
| 86 | + if (project.settings.isRemoteScenario) { |
| 87 | + createSourceCodeFiles(sources, "stub") |
| 88 | + } |
| 89 | + } |
56 | 90 |
|
57 |
| - refreshAndFindNioFile(filePath) |
| 91 | + private fun createSourceCodeFiles(sourceCodes: List<SourceCode>, fileKind: String) { |
| 92 | + sourceCodes.forEach { |
| 93 | + project.logger.info { "Write $fileKind file ${it.remotePath} to ${it.localPath}" } |
| 94 | + createFileWithText(it.localPath, it.content) |
58 | 95 | }
|
59 | 96 | }
|
60 | 97 |
|
61 |
| - private fun isGeneratedFileTestSourceFile(fileName: String) = fileName.endsWith("_test.cpp") |
| 98 | + override fun Testgen.TestsResponse.getProgress(): Util.Progress = progress |
| 99 | + |
| 100 | + private fun backupPreviousClientSarifReport(previousReportPaths: Path) { |
| 101 | + fun Number.pad2(): String = ("0$this").takeLast(2) |
| 102 | + |
| 103 | + if (previousReportPaths.exists()) { |
| 104 | + val ctime = Files.getLastModifiedTime(previousReportPaths) |
| 105 | + .toInstant() |
| 106 | + .atZone(ZoneId.systemDefault()) |
| 107 | + .toLocalDateTime() |
| 108 | + |
| 109 | + val newReportName = "project_code_analysis-" + |
| 110 | + ctime.year.toString() + |
| 111 | + (ctime.monthValue + 1).pad2() + |
| 112 | + ctime.dayOfMonth.pad2() + |
| 113 | + ctime.hour.pad2() + |
| 114 | + ctime.minute.pad2() + |
| 115 | + ctime.second.pad2() + |
| 116 | + ".sarif" |
| 117 | + val newPath = Paths.get(previousReportPaths.parent.toString(), newReportName) |
| 118 | + Files.move(previousReportPaths, newPath) |
| 119 | + } |
| 120 | + } |
62 | 121 |
|
63 | 122 | override fun onCompletion(exception: Throwable?) {
|
64 | 123 | super.onCompletion(exception)
|
|
0 commit comments