@@ -32,6 +32,7 @@ import org.utbot.features.FeatureExtractorFactoryImpl
32
32
import org.utbot.features.FeatureProcessorWithStatesRepetitionFactory
33
33
import org.utbot.framework.PathSelectorType
34
34
import org.utbot.framework.UtSettings
35
+ import org.utbot.framework.codegen.renderer.CgAbstractRenderer
35
36
import org.utbot.framework.plugin.api.util.id
36
37
import org.utbot.framework.plugin.api.util.withUtContext
37
38
import org.utbot.framework.plugin.services.JdkInfoService
@@ -49,7 +50,10 @@ private val javaHome = System.getenv("JAVA_HOME")
49
50
private val javacCmd = " $javaHome /bin/javac"
50
51
private val javaCmd = " $javaHome /bin/java"
51
52
52
- private const val compileAttempts = 2
53
+ // first attempt is for --add-opens
54
+ // second attempt is for removing test methods that still don't compile
55
+ // last attempt is for checking if final result compiles
56
+ private const val compileAttempts = 3
53
57
54
58
private data class UnnamedPackageInfo (val pack : String , val module : String )
55
59
@@ -62,7 +66,16 @@ private fun findAllNotExportedPackages(report: String): List<UnnamedPackageInfo>
62
66
}.toList().distinct()
63
67
}
64
68
65
- private fun compileClass (testDir : String , classPath : String , testClass : String ): Int {
69
+ private fun findErrorLines (report : String ): List <Int > {
70
+ // (\d+) is line number
71
+ // (:(\d+)) is optional column number
72
+ val regex = """ \.java:(\d+)(:(\d+))?: error""" .toRegex()
73
+ return regex.findAll(report).map {
74
+ it.groupValues[1 ].toInt() - 1
75
+ }.toList().distinct()
76
+ }
77
+
78
+ fun compileClassAndRemoveUncompilableTests (testDir : String , classPath : String , testClass : String ): Int = try {
66
79
val exports = mutableSetOf<UnnamedPackageInfo >()
67
80
var exitCode = 0
68
81
@@ -93,10 +106,48 @@ private fun compileClass(testDir: String, classPath: String, testClass: String):
93
106
if (errors.isNotEmpty())
94
107
logger.error { " Compilation errors: $errors " }
95
108
exports + = findAllNotExportedPackages(errors)
109
+ if (attemptNumber >= 1 ) {
110
+ val testFile = File (testClass)
111
+ val testClassLines = testFile.readLines()
112
+ val testStarts = testClassLines.withIndex()
113
+ .filter { it.value.contains(CgAbstractRenderer .TEST_METHOD_START_MARKER ) }
114
+ .map { it.index }
115
+ val testEnds = testClassLines.withIndex()
116
+ .filter { it.value.contains(CgAbstractRenderer .TEST_METHOD_END_MARKER ) }
117
+ .map { it.index }
118
+ val errorLines = findErrorLines(errors)
119
+ val errorRanges = errorLines.map { errorLine ->
120
+ // if error is outside test method, we can't fix that by removing test methods
121
+ val testStart = testStarts.filter { it <= errorLine }.maxOrNull() ? : return exitCode
122
+ val testEnd = testEnds.filter { it >= errorLine }.minOrNull() ? : return exitCode
123
+ testStart.. testEnd
124
+ }.distinct()
125
+ if (errorRanges.size > testStarts.size / 5.0 ) {
126
+ logger.error { " Over 20% of test are uncompilable" }
127
+ logger.error { " Speculating that something is wrong with compilation settings, keeping all tests" }
128
+ return exitCode
129
+ }
130
+ val linesToRemove = mutableSetOf<Int >()
131
+ errorRanges.forEach { linesToRemove.addAll(it) }
132
+ val removedText = testClassLines.withIndex()
133
+ .filter { it.index in linesToRemove }
134
+ .joinToString(" \n " ) { " ${it.index} : ${it.value} " }
135
+ logger.info { " Removed uncompilable tests:\n $removedText " }
136
+ testFile.writeText(testClassLines.filterIndexed { i, _ -> i !in linesToRemove }.joinToString(" \n " ))
137
+ }
96
138
}
97
139
}
98
140
99
- return exitCode
141
+ exitCode
142
+ } catch (e: Throwable ) {
143
+ logger.error(e) { " compileClass failed" }
144
+ 1
145
+ } finally {
146
+ val testFile = File (testClass)
147
+ testFile.writeText(testFile.readLines().filter {
148
+ ! it.contains(CgAbstractRenderer .TEST_METHOD_START_MARKER )
149
+ && ! it.contains(CgAbstractRenderer .TEST_METHOD_END_MARKER )
150
+ }.joinToString(" \n " ))
100
151
}
101
152
102
153
fun Array<String>.toText () = joinToString(separator = " ," )
@@ -181,7 +232,7 @@ interface Tool {
181
232
classStats.testClassFile = testClass
182
233
183
234
logger.info().measureTime({ " Compiling class ${testClass.absolutePath} " }) {
184
- val exitCode = compileClass (
235
+ val exitCode = compileClassAndRemoveUncompilableTests (
185
236
compiledTestDir.absolutePath,
186
237
project.compileClasspathString,
187
238
testClass.absolutePath
@@ -456,7 +507,7 @@ fun runEstimator(
456
507
if (UtSettings .pathSelectorType == PathSelectorType .ML_SELECTOR || UtSettings .pathSelectorType == PathSelectorType .TORCH_SELECTOR ) {
457
508
Predictors .stateRewardPredictor = EngineAnalyticsContext .mlPredictorFactory()
458
509
}
459
-
510
+
460
511
logger.info { " PathSelectorType: ${UtSettings .pathSelectorType} " }
461
512
if (UtSettings .pathSelectorType == PathSelectorType .ML_SELECTOR || UtSettings .pathSelectorType == PathSelectorType .TORCH_SELECTOR ) {
462
513
logger.info { " RewardModelPath: ${UtSettings .modelPath} " }
0 commit comments