@@ -22,6 +22,7 @@ import com.intellij.openapi.wm.ToolWindowManager
22
22
import com.intellij.psi.JavaDirectoryService
23
23
import com.intellij.psi.PsiClass
24
24
import com.intellij.psi.PsiClassOwner
25
+ import com.intellij.psi.PsiComment
25
26
import com.intellij.psi.PsiDirectory
26
27
import com.intellij.psi.PsiDocumentManager
27
28
import com.intellij.psi.PsiElement
@@ -49,6 +50,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
49
50
import org.jetbrains.kotlin.psi.psiUtil.endOffset
50
51
import org.jetbrains.kotlin.psi.psiUtil.startOffset
51
52
import org.jetbrains.kotlin.scripting.resolve.classId
53
+ import org.jetbrains.plugins.groovy.lang.psi.util.childrenOfType
52
54
import org.utbot.common.HTML_LINE_SEPARATOR
53
55
import org.utbot.common.PathUtil.toHtmlLinkTag
54
56
import org.utbot.common.appendHtmlLine
@@ -151,33 +153,18 @@ object CodeGenerationController {
151
153
152
154
run (EDT_LATER ) {
153
155
waitForCountDown(latch, timeout = 100 , timeUnit = TimeUnit .MILLISECONDS ) {
154
- val project = model.project
155
- val language = model.codegenLanguage
156
- val testModule = model.testModule
157
-
158
- val existingUtilClass = language.getUtilClassOrNull(project, testModule)
159
-
160
156
val utilClassKind = utilClassListener.requiredUtilClassKind
161
157
? : return @waitForCountDown // no util class needed
162
158
163
- val utilClassExists = existingUtilClass != null
164
- val mockFrameworkNotUsed = ! utilClassListener.mockFrameworkUsed
165
-
166
- if (utilClassExists && mockFrameworkNotUsed) {
167
- // If util class already exists and mock framework is not used,
168
- // then existing util class is enough, and we don't need to generate a new one.
169
- // That's because both regular and mock versions of util class can work
170
- // with tests that do not use mocks, so we do not have to worry about
171
- // version of util class that we have at the moment.
172
- return @waitForCountDown
159
+ val existingUtilClass = model.codegenLanguage.getUtilClassOrNull(model.project, model.testModule)
160
+ if (shouldCreateOrUpdateUtilClass(existingUtilClass, utilClassListener)) {
161
+ createOrUpdateUtilClass(
162
+ testDirectory = baseTestDirectory,
163
+ utilClassKind = utilClassKind,
164
+ existingUtilClass = existingUtilClass,
165
+ model = model
166
+ )
173
167
}
174
-
175
- createOrUpdateUtilClass(
176
- testDirectory = baseTestDirectory,
177
- utilClassKind = utilClassKind,
178
- existingUtilClass = existingUtilClass,
179
- model = model
180
- )
181
168
}
182
169
}
183
170
@@ -208,6 +195,39 @@ object CodeGenerationController {
208
195
}
209
196
}
210
197
198
+ private fun shouldCreateOrUpdateUtilClass (existingUtilClass : PsiFile ? , utilClassListener : UtilClassListener ): Boolean {
199
+ val existingUtilClassVersion = existingUtilClass?.utilClassVersionOrNull
200
+ // TODO: here should be the current version of UTBot
201
+ val newUtilClassVersion = " 1.0-SNAPSHOT"
202
+ val versionIsUpdated = existingUtilClassVersion != newUtilClassVersion
203
+
204
+ val mockFrameworkNotUsed = ! utilClassListener.mockFrameworkUsed
205
+
206
+ val utilClassExists = existingUtilClass != null
207
+
208
+ if (! utilClassExists) {
209
+ // If no util class exists, then we should create a new one.
210
+ return true
211
+ }
212
+
213
+ if (versionIsUpdated) {
214
+ // If an existing util class is out of date,
215
+ // then we must overwrite it with a newer version.
216
+ return true
217
+ }
218
+
219
+ if (mockFrameworkNotUsed) {
220
+ // If util class already exists and mock framework is not used,
221
+ // then existing util class is enough, and we don't need to generate a new one.
222
+ // That's because both regular and mock versions of util class can work
223
+ // with tests that do not use mocks, so we do not have to worry about
224
+ // version of util class that we have at the moment.
225
+ return false
226
+ }
227
+
228
+ return true
229
+ }
230
+
211
231
/* *
212
232
* If [existingUtilClass] is null (no util class exists), then we create package directories for util class,
213
233
* create util class itself, and put it into the corresponding directory.
@@ -312,6 +332,25 @@ object CodeGenerationController {
312
332
return utUtilsFile
313
333
}
314
334
335
+ /* *
336
+ * Util class must have a comment that specifies the version of UTBot it was generated with.
337
+ * This property represents the version specified by this comment if it exists. Otherwise, the property is `null`.
338
+ */
339
+ private val PsiFile .utilClassVersionOrNull: String?
340
+ get() = runReadAction {
341
+ childrenOfType<PsiComment >()
342
+ .map { comment -> comment.text }
343
+ .firstOrNull { text -> UTBOT_VERSION_PREFIX in text }
344
+ ?.substringAfterLast(UTBOT_VERSION_PREFIX )
345
+ ?.trim()
346
+ }
347
+
348
+ /* *
349
+ * Util class must have a comment that specifies the version of UTBot it was generated with.
350
+ * This prefix is the start of this comment. The version of UTBot goes after it in the comment.
351
+ */
352
+ private const val UTBOT_VERSION_PREFIX = " UTBot version:"
353
+
315
354
/* *
316
355
* @param srcClass class under test
317
356
* @return name of the package of a given [srcClass].
0 commit comments