@@ -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.allNestedClasses
@@ -159,33 +161,18 @@ object CodeGenerationController {
159
161
160
162
run (EDT_LATER ) {
161
163
waitForCountDown(latch, timeout = 100 , timeUnit = TimeUnit .MILLISECONDS ) {
162
- val project = model.project
163
- val language = model.codegenLanguage
164
- val testModule = model.testModule
165
-
166
- val existingUtilClass = language.getUtilClassOrNull(project, testModule)
167
-
168
164
val utilClassKind = utilClassListener.requiredUtilClassKind
169
165
? : return @waitForCountDown // no util class needed
170
166
171
- val utilClassExists = existingUtilClass != null
172
- val mockFrameworkNotUsed = ! utilClassListener.mockFrameworkUsed
173
-
174
- if (utilClassExists && mockFrameworkNotUsed) {
175
- // If util class already exists and mock framework is not used,
176
- // then existing util class is enough, and we don't need to generate a new one.
177
- // That's because both regular and mock versions of util class can work
178
- // with tests that do not use mocks, so we do not have to worry about
179
- // version of util class that we have at the moment.
180
- return @waitForCountDown
167
+ val existingUtilClass = model.codegenLanguage.getUtilClassOrNull(model.project, model.testModule)
168
+ if (shouldCreateOrUpdateUtilClass(existingUtilClass, utilClassListener)) {
169
+ createOrUpdateUtilClass(
170
+ testDirectory = baseTestDirectory,
171
+ utilClassKind = utilClassKind,
172
+ existingUtilClass = existingUtilClass,
173
+ model = model
174
+ )
181
175
}
182
-
183
- createOrUpdateUtilClass(
184
- testDirectory = baseTestDirectory,
185
- utilClassKind = utilClassKind,
186
- existingUtilClass = existingUtilClass,
187
- model = model
188
- )
189
176
}
190
177
}
191
178
@@ -216,6 +203,39 @@ object CodeGenerationController {
216
203
}
217
204
}
218
205
206
+ private fun shouldCreateOrUpdateUtilClass (existingUtilClass : PsiFile ? , utilClassListener : UtilClassListener ): Boolean {
207
+ val existingUtilClassVersion = existingUtilClass?.utilClassVersionOrNull
208
+ // TODO: here should be the current version of UTBot
209
+ val newUtilClassVersion = " 1.0-SNAPSHOT"
210
+ val versionIsUpdated = existingUtilClassVersion != newUtilClassVersion
211
+
212
+ val mockFrameworkNotUsed = ! utilClassListener.mockFrameworkUsed
213
+
214
+ val utilClassExists = existingUtilClass != null
215
+
216
+ if (! utilClassExists) {
217
+ // If no util class exists, then we should create a new one.
218
+ return true
219
+ }
220
+
221
+ if (versionIsUpdated) {
222
+ // If an existing util class is out of date,
223
+ // then we must overwrite it with a newer version.
224
+ return true
225
+ }
226
+
227
+ if (mockFrameworkNotUsed) {
228
+ // If util class already exists and mock framework is not used,
229
+ // then existing util class is enough, and we don't need to generate a new one.
230
+ // That's because both regular and mock versions of util class can work
231
+ // with tests that do not use mocks, so we do not have to worry about
232
+ // version of util class that we have at the moment.
233
+ return false
234
+ }
235
+
236
+ return true
237
+ }
238
+
219
239
/* *
220
240
* If [existingUtilClass] is null (no util class exists), then we create package directories for util class,
221
241
* create util class itself, and put it into the corresponding directory.
@@ -320,6 +340,25 @@ object CodeGenerationController {
320
340
return utUtilsFile
321
341
}
322
342
343
+ /* *
344
+ * Util class must have a comment that specifies the version of UTBot it was generated with.
345
+ * This property represents the version specified by this comment if it exists. Otherwise, the property is `null`.
346
+ */
347
+ private val PsiFile .utilClassVersionOrNull: String?
348
+ get() = runReadAction {
349
+ childrenOfType<PsiComment >()
350
+ .map { comment -> comment.text }
351
+ .firstOrNull { text -> UTBOT_VERSION_PREFIX in text }
352
+ ?.substringAfterLast(UTBOT_VERSION_PREFIX )
353
+ ?.trim()
354
+ }
355
+
356
+ /* *
357
+ * Util class must have a comment that specifies the version of UTBot it was generated with.
358
+ * This prefix is the start of this comment. The version of UTBot goes after it in the comment.
359
+ */
360
+ private const val UTBOT_VERSION_PREFIX = " UTBot version:"
361
+
323
362
/* *
324
363
* @param srcClass class under test
325
364
* @return name of the package of a given [srcClass].
0 commit comments