@@ -48,7 +48,7 @@ import java.nio.file.Path
4848import java.nio.file.Paths
4949import java.util.concurrent.TimeUnit
5050import kotlin.io.path.pathString
51- import org.utbot.framework.plugin.api.util.Lock
51+ import org.utbot.framework.plugin.api.util.LockFile
5252
5353object UtTestsDialogProcessor {
5454 private val logger = KotlinLogging .logger {}
@@ -122,150 +122,153 @@ object UtTestsDialogProcessor {
122122 promise.onSuccess {
123123 if (it.hasErrors() || it.isAborted)
124124 return @onSuccess
125- if (! Lock .lock()) {
126- return @onSuccess
127- }
128125
129126 (object : Task .Backgroundable (project, " Generate tests" ) {
130127
131128 override fun run (indicator : ProgressIndicator ) {
132- val ldef = LifetimeDefinition ()
133- ldef.onTermination { Lock .unlock() }
134- ldef.terminateOnException { lifetime ->
135- val secondsTimeout = TimeUnit .MILLISECONDS .toSeconds(model.timeout)
136-
137- indicator.isIndeterminate = false
138- updateIndicator(indicator, ProgressRange .SOLVING , " Generate tests: read classes" , 0.0 )
139-
140- val buildPaths = ReadAction
141- .nonBlocking<BuildPaths ?> { findPaths(model.srcClasses) }
142- .executeSynchronously()
143- ? : return
144-
145- val (buildDirs, classpath, classpathList, pluginJarsPath) = buildPaths
146-
147- val testSetsByClass = mutableMapOf<PsiClass , RdTestGenerationResult >()
148- val psi2KClass = mutableMapOf<PsiClass , ClassId >()
149- var processedClasses = 0
150- val totalClasses = model.srcClasses.size
151-
152- val proc = EngineProcess (lifetime, project)
153-
154- proc.setupUtContext(buildDirs + classpathList)
155- proc.createTestGenerator(
156- buildDirs,
157- classpath,
158- pluginJarsPath.joinToString(separator = File .pathSeparator),
159- JdkInfoService .provide()
160- ) {
161- ApplicationManager .getApplication().runReadAction(Computable {
162- indicator.isCanceled
163- })
164- }
129+ if (! LockFile .lock()) {
130+ return
131+ }
132+ try {
133+ val ldef = LifetimeDefinition ()
134+ ldef.terminateOnException { lifetime ->
135+ val secondsTimeout = TimeUnit .MILLISECONDS .toSeconds(model.timeout)
165136
166- for (srcClass in model.srcClasses) {
167- val (methods, className) = DumbService .getInstance(project)
168- .runReadActionInSmartMode(Computable {
169- val canonicalName = srcClass.canonicalName
170- val classId = proc.obtainClassId(canonicalName)
171- psi2KClass[srcClass] = classId
172-
173- val srcMethods = if (model.extractMembersFromSrcClasses) {
174- val chosenMethods = model.selectedMembers.filter { it.member is PsiMethod }
175- val chosenNestedClasses =
176- model.selectedMembers.mapNotNull { it.member as ? PsiClass }
177- chosenMethods + chosenNestedClasses.flatMap {
178- it.extractClassMethodsIncludingNested(false )
179- }
180- } else {
181- srcClass.extractClassMethodsIncludingNested(false )
182- }
183- proc.findMethodsInClassMatchingSelected(classId, srcMethods) to srcClass.name
184- })
137+ indicator.isIndeterminate = false
138+ updateIndicator(indicator, ProgressRange .SOLVING , " Generate tests: read classes" , 0.0 )
185139
186- if (methods.isEmpty()) {
187- logger.error { " No methods matching selected found in class $className ." }
188- continue
140+ val buildPaths = ReadAction
141+ .nonBlocking<BuildPaths ?> { findPaths(model.srcClasses) }
142+ .executeSynchronously()
143+ ? : return
144+
145+ val (buildDirs, classpath, classpathList, pluginJarsPath) = buildPaths
146+
147+ val testSetsByClass = mutableMapOf<PsiClass , RdTestGenerationResult >()
148+ val psi2KClass = mutableMapOf<PsiClass , ClassId >()
149+ var processedClasses = 0
150+ val totalClasses = model.srcClasses.size
151+
152+ val proc = EngineProcess (lifetime, project)
153+
154+ proc.setupUtContext(buildDirs + classpathList)
155+ proc.createTestGenerator(
156+ buildDirs,
157+ classpath,
158+ pluginJarsPath.joinToString(separator = File .pathSeparator),
159+ JdkInfoService .provide()
160+ ) {
161+ ApplicationManager .getApplication().runReadAction(Computable {
162+ indicator.isCanceled
163+ })
189164 }
190165
191- if (totalClasses > 1 ) {
192- updateIndicator(
193- indicator,
194- ProgressRange .SOLVING ,
195- " Generate test cases for class $className " ,
196- processedClasses.toDouble() / totalClasses
197- )
198- }
166+ for (srcClass in model.srcClasses) {
167+ val (methods, className) = DumbService .getInstance(project)
168+ .runReadActionInSmartMode(Computable {
169+ val canonicalName = srcClass.canonicalName
170+ val classId = proc.obtainClassId(canonicalName)
171+ psi2KClass[srcClass] = classId
172+
173+ val srcMethods = if (model.extractMembersFromSrcClasses) {
174+ val chosenMethods = model.selectedMembers.filter { it.member is PsiMethod }
175+ val chosenNestedClasses =
176+ model.selectedMembers.mapNotNull { it.member as ? PsiClass }
177+ chosenMethods + chosenNestedClasses.flatMap {
178+ it.extractClassMethodsIncludingNested(false )
179+ }
180+ } else {
181+ srcClass.extractClassMethodsIncludingNested(false )
182+ }
183+ proc.findMethodsInClassMatchingSelected(classId, srcMethods) to srcClass.name
184+ })
199185
200- // set timeout for concrete execution and for generated tests
201- UtSettings .concreteExecutionTimeoutInChildProcess =
202- model.hangingTestsTimeout.timeoutMs
186+ if (methods.isEmpty()) {
187+ logger.error { " No methods matching selected found in class $className ." }
188+ continue
189+ }
203190
204- UtSettings .useCustomJavaDocTags =
205- model.commentStyle == JavaDocCommentStyle .CUSTOM_JAVADOC_TAGS
191+ if (totalClasses > 1 ) {
192+ updateIndicator(
193+ indicator,
194+ ProgressRange .SOLVING ,
195+ " Generate test cases for class $className " ,
196+ processedClasses.toDouble() / totalClasses
197+ )
198+ }
206199
207- UtSettings .enableSummariesGeneration = model.enableSummariesGeneration
200+ // set timeout for concrete execution and for generated tests
201+ UtSettings .concreteExecutionTimeoutInChildProcess =
202+ model.hangingTestsTimeout.timeoutMs
208203
209- val searchDirectory = ReadAction
210- .nonBlocking<Path > {
211- project.basePath?.let { Paths .get(it) }
212- ? : Paths .get(srcClass.containingFile.virtualFile.parent.path)
213- }
214- .executeSynchronously()
204+ UtSettings .useCustomJavaDocTags =
205+ model.commentStyle == JavaDocCommentStyle .CUSTOM_JAVADOC_TAGS
215206
216- withStaticsSubstitutionRequired(true ) {
217- val mockFrameworkInstalled = model.mockFramework?.isInstalled ? : true
218-
219- val rdGenerateResult = proc.generate(
220- mockFrameworkInstalled,
221- model.staticsMocking.isConfigured,
222- model.conflictTriggers,
223- methods,
224- model.mockStrategy,
225- model.chosenClassesToMockAlways,
226- model.timeout,
227- model.timeout,
228- true ,
229- UtSettings .useFuzzing,
230- project.service<Settings >().fuzzingValue,
231- searchDirectory.pathString
232- )
233-
234- if (rdGenerateResult.notEmptyCases == 0 ) {
235- if (model.srcClasses.size > 1 ) {
236- logger.error { " Failed to generate any tests cases for class $className " }
207+ UtSettings .enableSummariesGeneration = model.enableSummariesGeneration
208+
209+ val searchDirectory = ReadAction
210+ .nonBlocking<Path > {
211+ project.basePath?.let { Paths .get(it) }
212+ ? : Paths .get(srcClass.containingFile.virtualFile.parent.path)
213+ }
214+ .executeSynchronously()
215+
216+ withStaticsSubstitutionRequired(true ) {
217+ val mockFrameworkInstalled = model.mockFramework?.isInstalled ? : true
218+
219+ val rdGenerateResult = proc.generate(
220+ mockFrameworkInstalled,
221+ model.staticsMocking.isConfigured,
222+ model.conflictTriggers,
223+ methods,
224+ model.mockStrategy,
225+ model.chosenClassesToMockAlways,
226+ model.timeout,
227+ model.timeout,
228+ true ,
229+ UtSettings .useFuzzing,
230+ project.service<Settings >().fuzzingValue,
231+ searchDirectory.pathString
232+ )
233+
234+ if (rdGenerateResult.notEmptyCases == 0 ) {
235+ if (model.srcClasses.size > 1 ) {
236+ logger.error { " Failed to generate any tests cases for class $className " }
237+ } else {
238+ showErrorDialogLater(
239+ model.project,
240+ errorMessage(className, secondsTimeout),
241+ title = " Failed to generate unit tests for class $className "
242+ )
243+ }
237244 } else {
238- showErrorDialogLater(
239- model.project,
240- errorMessage(className, secondsTimeout),
241- title = " Failed to generate unit tests for class $className "
242- )
245+ testSetsByClass[srcClass] = rdGenerateResult
243246 }
244- } else {
245- testSetsByClass[srcClass] = rdGenerateResult
246247 }
248+ processedClasses++
247249 }
248- processedClasses++
249- }
250250
251- if (processedClasses == 0 ) {
252- invokeLater {
253- Messages .showInfoMessage(
254- model.project,
255- " No methods for test generation were found among selected items" ,
256- " No methods found"
257- )
251+ if (processedClasses == 0 ) {
252+ invokeLater {
253+ Messages .showInfoMessage(
254+ model.project,
255+ " No methods for test generation were found among selected items" ,
256+ " No methods found"
257+ )
258+ }
259+ return
258260 }
259- return
260- }
261- updateIndicator(indicator, ProgressRange .CODEGEN , " Generate code for tests" , 0.0 )
262- // Commented out to generate tests for collected executions even if action was canceled.
263- // indicator.checkCanceled()
261+ updateIndicator(indicator, ProgressRange .CODEGEN , " Generate code for tests" , 0.0 )
262+ // Commented out to generate tests for collected executions even if action was canceled.
263+ // indicator.checkCanceled()
264264
265- invokeLater {
266- generateTests(model, testSetsByClass, psi2KClass, proc, indicator)
267- logger.info { " Generation complete" }
265+ invokeLater {
266+ generateTests(model, testSetsByClass, psi2KClass, proc, indicator)
267+ logger.info { " Generation complete" }
268+ }
268269 }
270+ } finally {
271+ LockFile .unlock()
269272 }
270273 }
271274 }).queue()
0 commit comments