@@ -28,15 +28,14 @@ import org.utbot.intellij.plugin.ui.utils.findFrameworkLibrary
2828import org.utbot.intellij.plugin.ui.utils.getOrCreateTestResourcesPath
2929import org.utbot.intellij.plugin.ui.utils.kotlinTargetPlatform
3030import org.utbot.intellij.plugin.ui.utils.parseVersion
31- import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots
3231import org.utbot.intellij.plugin.ui.utils.testResourceRootTypes
32+ import org.utbot.intellij.plugin.ui.utils.addSourceRootIfAbsent
3333import org.utbot.intellij.plugin.ui.utils.testRootType
3434import com.intellij.ide.impl.ProjectNewWindowDoNotAskOption
3535import com.intellij.openapi.application.runWriteAction
3636import com.intellij.openapi.command.WriteCommandAction
3737import com.intellij.openapi.components.service
3838import com.intellij.openapi.options.ShowSettingsUtil
39- import com.intellij.openapi.projectRoots.JavaSdkVersion
4039import com.intellij.openapi.roots.ContentEntry
4140import com.intellij.openapi.roots.DependencyScope
4241import com.intellij.openapi.roots.ExternalLibraryDescriptor
@@ -48,10 +47,12 @@ import com.intellij.openapi.ui.DialogPanel
4847import com.intellij.openapi.ui.DialogWrapper
4948import com.intellij.openapi.ui.Messages
5049import com.intellij.openapi.ui.ValidationInfo
51- import com.intellij.openapi.ui.popup.IconButton
50+ import com.intellij.openapi.util.Computable
51+ import com.intellij.openapi.vfs.StandardFileSystems
5252import com.intellij.openapi.vfs.VfsUtil
5353import com.intellij.openapi.vfs.VfsUtilCore.urlToPath
5454import com.intellij.openapi.vfs.VirtualFile
55+ import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile
5556import com.intellij.psi.PsiClass
5657import com.intellij.psi.PsiManager
5758import com.intellij.psi.PsiMethod
@@ -74,14 +75,9 @@ import com.intellij.ui.layout.Row
7475import com.intellij.ui.layout.panel
7576import com.intellij.util.IncorrectOperationException
7677import com.intellij.util.io.exists
77- import com.intellij.util.lang.JavaVersion
78- import com.intellij.util.ui.JBUI
79- import com.intellij.util.ui.JBUI.Borders.empty
80- import com.intellij.util.ui.JBUI.Borders.merge
81- import com.intellij.util.ui.JBUI.scale
8278import com.intellij.util.ui.JBUI.size
79+ import com.intellij.util.ui.JBUI
8380import com.intellij.util.ui.UIUtil
84- import com.intellij.util.ui.components.BorderLayoutPanel
8581import java.awt.BorderLayout
8682import java.nio.file.Files
8783import java.nio.file.Path
@@ -274,16 +270,16 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
274270
275271 private fun getTestRoot () : VirtualFile ? {
276272 model.testSourceRoot?.let {
277- if (it.isDirectory) return it
273+ if (it.isDirectory || it is FakeVirtualFile ) return it
278274 }
279275 return null
280276 }
281277
282278 override fun doValidate (): ValidationInfo ? {
283- if (getTestRoot() == null ) {
284- return ValidationInfo (" Test source root is not configured" , testSourceFolderField.childComponent)
285- }
286- if (getRootDirectoryAndContentEntry( ) == null ) {
279+ val testRoot = getTestRoot()
280+ ? : return ValidationInfo (" Test source root is not configured" , testSourceFolderField.childComponent)
281+
282+ if (findReadOnlyContentEntry(testRoot ) == null ) {
287283 return ValidationInfo (" Test source root is located out of content entry" , testSourceFolderField.childComponent)
288284 }
289285
@@ -373,18 +369,33 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
373369 * Creates test source root if absent and target packages for tests.
374370 */
375371 private fun createTestRootAndPackages (): Boolean {
376- val (sourceRoot, contentEntry) = getRootDirectoryAndContentEntry() ? : return false
377- val modifiableModel = ModuleRootManager .getInstance(model.testModule).modifiableModel
378- VfsUtil .createDirectoryIfMissing(urlToPath(sourceRoot.url))
379- contentEntry.addSourceFolder(sourceRoot.url, codegenLanguages.item.testRootType())
380- WriteCommandAction .runWriteCommandAction(model.project) { modifiableModel.commit() }
372+ model.testSourceRoot = createDirectoryIfMissing(model.testSourceRoot)
373+ val testSourceRoot = model.testSourceRoot ? : return false
374+ if (model.testSourceRoot?.isDirectory != true ) return false
375+ if (getOrCreateTestRoot(testSourceRoot)) {
376+ if (cbSpecifyTestPackage.isSelected) {
377+ createSelectedPackage(testSourceRoot)
378+ } else {
379+ createPackagesByClasses(testSourceRoot)
380+ }
381+ return true
382+ }
383+ return false
384+ }
381385
382- if (cbSpecifyTestPackage.isSelected) {
383- createSelectedPackage(sourceRoot)
386+ private fun createDirectoryIfMissing (dir : VirtualFile ? ): VirtualFile ? {
387+ val file = if (dir is FakeVirtualFile ) {
388+ WriteCommandAction .runWriteCommandAction(model.project, Computable <VirtualFile > {
389+ VfsUtil .createDirectoryIfMissing(dir.path)
390+ })
384391 } else {
385- createPackagesByClasses(sourceRoot)
392+ dir
393+ }? : return null
394+ return if (VfsUtil .virtualToIoFile(file).isFile) {
395+ null
396+ } else {
397+ StandardFileSystems .local().findFileByPath(file.path)
386398 }
387- return true
388399 }
389400
390401 private fun createPackagesByClasses (testSourceRoot : VirtualFile ) {
@@ -413,12 +424,33 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
413424 " Generation error"
414425 )
415426
416- private fun getRootDirectoryAndContentEntry () : Pair <VirtualFile , ContentEntry >? {
417- val testSourceRoot = getTestRoot()? : return null
418- val contentEntry = ModuleRootManager .getInstance(model.testModule).contentEntries
427+ private fun findReadOnlyContentEntry (testSourceRoot : VirtualFile ? ): ContentEntry ? {
428+ if (testSourceRoot == null ) return null
429+ if (testSourceRoot is FakeVirtualFile ) {
430+ return findReadOnlyContentEntry(testSourceRoot.parent)
431+ }
432+ return ModuleRootManager .getInstance(model.testModule).contentEntries
419433 .filterNot { it.file == null }
420- .firstOrNull { VfsUtil .isAncestor(it.file!! , testSourceRoot, true ) } ? : return null
421- return Pair (testSourceRoot, contentEntry)
434+ .firstOrNull { VfsUtil .isAncestor(it.file!! , testSourceRoot, false ) }
435+ }
436+
437+ private fun getOrCreateTestRoot (testSourceRoot : VirtualFile ): Boolean {
438+ val modifiableModel = ModuleRootManager .getInstance(model.testModule).modifiableModel
439+ try {
440+ val contentEntry = modifiableModel.contentEntries
441+ .filterNot { it.file == null }
442+ .firstOrNull { VfsUtil .isAncestor(it.file!! , testSourceRoot, true ) }
443+ ? : return false
444+
445+ contentEntry.addSourceRootIfAbsent(
446+ modifiableModel,
447+ testSourceRoot.url,
448+ codegenLanguages.item.testRootType()
449+ )
450+ return true
451+ } finally {
452+ if (modifiableModel.isWritable && ! modifiableModel.isDisposed) modifiableModel.dispose()
453+ }
422454 }
423455
424456 private fun createPackageWrapper (packageName : String? ): PackageWrapper =
@@ -648,7 +680,14 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
648680 itemsToHelpTooltip.forEach { (box, tooltip) -> box.setHelpTooltipTextChanger(tooltip) }
649681
650682 testSourceFolderField.childComponent.addActionListener { event ->
651- model.testSourceRoot = pathToFile((event.source as JComboBox <* >).selectedItem as String )
683+ with ((event.source as JComboBox <* >).selectedItem) {
684+ if (this is VirtualFile ) {
685+ model.testSourceRoot = this @with
686+ }
687+ else {
688+ model.testSourceRoot = null
689+ }
690+ }
652691 }
653692
654693 mockStrategies.addActionListener { event ->
@@ -700,14 +739,6 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
700739 }
701740 }
702741
703- private fun pathToFile (path : String ): VirtualFile ? {
704- val relativePath = path.substring(" .../" .length).replace(' \\ ' , ' /' )
705- return model.testModule
706- .suitableTestSourceRoots()
707- .firstOrNull { it.path.contains(relativePath) }
708- }
709-
710-
711742 private lateinit var currentFrameworkItem: TestFramework
712743
713744 // We would like to remove JUnit4 from framework list in parametrized mode
0 commit comments