Skip to content

Commit 67bd15d

Browse files
authored
Improve the appearance of paths in Spring Config Selection ComboBox #2079 (#2096)
1 parent 7b5463c commit 67bd15d

File tree

2 files changed

+124
-11
lines changed

2 files changed

+124
-11
lines changed

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ import com.intellij.ui.layout.ComboBoxPredicate
6565
import com.intellij.ui.layout.Row
6666
import com.intellij.ui.layout.enableIf
6767
import com.intellij.ui.layout.panel
68-
import com.intellij.ui.layout.selectedValueMatches
6968
import com.intellij.util.IncorrectOperationException
7069
import com.intellij.util.io.exists
7170
import com.intellij.util.lang.JavaVersion
@@ -120,7 +119,6 @@ import org.utbot.framework.plugin.api.MockFramework
120119
import org.utbot.framework.plugin.api.MockFramework.MOCKITO
121120
import org.utbot.framework.plugin.api.MockStrategyApi
122121
import org.utbot.framework.plugin.api.TreatOverflowAsError
123-
import org.utbot.framework.plugin.api.isSummarizationCompatible
124122
import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FILE_CONTENT
125123
import org.utbot.framework.plugin.api.utils.MOCKITO_EXTENSIONS_FOLDER
126124
import org.utbot.framework.plugin.api.utils.MOCKITO_MOCKMAKER_FILE_NAME
@@ -152,8 +150,10 @@ import org.utbot.intellij.plugin.ui.utils.parseVersion
152150
import org.utbot.intellij.plugin.ui.utils.testResourceRootTypes
153151
import org.utbot.intellij.plugin.ui.utils.testRootType
154152
import org.utbot.intellij.plugin.util.IntelliJApiHelper
153+
import org.utbot.intellij.plugin.util.SpringConfigurationsHelper
155154
import org.utbot.intellij.plugin.util.extractFirstLevelMembers
156155
import org.utbot.intellij.plugin.util.findSdkVersion
156+
import java.io.File
157157
import java.time.LocalDateTime
158158
import java.time.format.DateTimeFormatter
159159
import java.util.*
@@ -192,12 +192,10 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
192192
private val codegenLanguages = createComboBox(CodegenLanguage.values())
193193
private val testFrameworks = createComboBox(TestFramework.allItems.toTypedArray())
194194

195-
private val modelSpringConfigs = setOf(
196-
null to listOf(NO_SPRING_CONFIGURATION_OPTION),
197-
"Java-based configurations" to model.getSortedSpringConfigurationClasses(),
198-
"XML-based configurations" to model.getSpringXMLConfigurationFiles()
199-
)
200-
private val springConfig = createComboBoxWithSeparatorsForSpringConfigs(modelSpringConfigs)
195+
private val javaConfigurationHelper = SpringConfigurationsHelper(".")
196+
private val xmlConfigurationHelper = SpringConfigurationsHelper(File.separator)
197+
198+
private val springConfig = createComboBoxWithSeparatorsForSpringConfigs(shortenConfigurationNames())
201199

202200
private val mockStrategies = createComboBox(MockStrategyApi.values())
203201
private val staticsMocking = JCheckBox("Mock static methods")
@@ -223,6 +221,20 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
223221
parametrizedTestSources to null
224222
)
225223

224+
private fun shortenConfigurationNames(): Set<Pair<String?, Collection<String>>> {
225+
val shortenedSortedSpringConfigurationClasses =
226+
javaConfigurationHelper.shortenSpringConfigNames(model.getSortedSpringConfigurationClasses())
227+
228+
val shortenedSpringXMLConfigurationFiles =
229+
xmlConfigurationHelper.shortenSpringConfigNames(model.getSpringXMLConfigurationFiles())
230+
231+
return setOf(
232+
null to listOf(NO_SPRING_CONFIGURATION_OPTION),
233+
"Java-based configurations" to shortenedSortedSpringConfigurationClasses,
234+
"XML-based configurations" to shortenedSpringXMLConfigurationFiles
235+
)
236+
}
237+
226238
private fun <T : CodeGenerationSettingItem> createComboBox(values: Array<T>) : ComboBox<T> {
227239
val comboBox = object:ComboBox<T>(DefaultComboBoxModel(values)) {
228240
var maxWidth = 0
@@ -580,7 +592,17 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
580592
model.typeReplacementApproach =
581593
when (springConfig.item.getItem()) {
582594
NO_SPRING_CONFIGURATION_OPTION -> TypeReplacementApproach.DoNotReplace
583-
else -> TypeReplacementApproach.ReplaceIfPossible(springConfig.item.getItem().toString())
595+
else -> {
596+
val shortConfigName = springConfig.item.getItem().toString()
597+
//TODO: avoid this check on xml here, merge two helpers into one
598+
val fullConfigName = if (shortConfigName.endsWith(".xml")) {
599+
xmlConfigurationHelper.restoreFullName(shortConfigName)
600+
} else {
601+
javaConfigurationHelper.restoreFullName(shortConfigName)
602+
}
603+
604+
TypeReplacementApproach.ReplaceIfPossible(fullConfigName)
605+
}
584606
}
585607

586608
val settings = model.project.service<Settings>()
@@ -1115,8 +1137,7 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m
11151137

11161138
private fun updateSpringConfigurationEnabled() {
11171139
// We check for > 1 because there is already extra-dummy NO_SPRING_CONFIGURATION_OPTION option
1118-
springConfig.isEnabled = model.projectType == ProjectType.Spring
1119-
&& modelSpringConfigs.size > 1
1140+
springConfig.isEnabled = model.projectType == ProjectType.Spring && springConfig.itemCount > 1
11201141
}
11211142

11221143
private fun staticsMockingConfigured(): Boolean {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.utbot.intellij.plugin.util
2+
3+
/**
4+
* This class is a converter between full Spring configuration names and shortened versions.
5+
*
6+
* Shortened versions are represented on UI.
7+
* Full names are used in further analysis in utbot-spring-analyzer.
8+
*
9+
* The idea of this implementation is to append parent directories to the file name until all names become unique.
10+
*
11+
* Example:
12+
* - [["config.web.WebConfig", "config.web2.WebConfig", "config.web.AnotherConfig"]]
13+
* ->
14+
* [["web.WebConfig", "web2.WebConfig", "AnotherConfig"]]
15+
*/
16+
class SpringConfigurationsHelper(val separator: String) {
17+
18+
private val nameToInfo = mutableMapOf<String, NameInfo>()
19+
20+
inner class NameInfo(val fullName: String) {
21+
val shortenedName: String
22+
get() = innerShortName
23+
24+
private val pathFragments: MutableList<String> = fullName.split(separator).toMutableList()
25+
private var innerShortName = pathFragments.removeLast()
26+
27+
fun enlargeShortName(): Boolean {
28+
if (pathFragments.isEmpty()) {
29+
return false
30+
}
31+
32+
val lastElement = pathFragments.removeLast()
33+
innerShortName = "${lastElement}$separator$innerShortName"
34+
return true
35+
}
36+
}
37+
38+
fun restoreFullName(shortenedName: String): String =
39+
nameToInfo
40+
.values
41+
.singleOrNull { it.shortenedName == shortenedName }
42+
?.fullName
43+
?: error("Full name of configuration file cannot be restored by shortened name $shortenedName")
44+
45+
fun shortenSpringConfigNames(fullNames: Set<String>): Set<String> {
46+
fullNames.forEach { nameToInfo[it] = NameInfo(it) }
47+
var nameInfoCollection = nameToInfo.values
48+
49+
// this cycle continues until all shortenedNames become unique
50+
while (nameInfoCollection.size != nameInfoCollection.distinctBy { it.shortenedName }.size) {
51+
nameInfoCollection = nameInfoCollection.sortedBy { it.shortenedName }.toMutableList()
52+
53+
var index = 0
54+
while(index < nameInfoCollection.size){
55+
val curShortenedPath = nameInfoCollection[index].shortenedName
56+
57+
// here we search a block of shortened paths that are equivalent
58+
// and must be enlarged with new fragment so on.
59+
var maxIndexWithSamePath = index
60+
while (maxIndexWithSamePath < nameInfoCollection.size) {
61+
if (nameInfoCollection[maxIndexWithSamePath].shortenedName == curShortenedPath) {
62+
maxIndexWithSamePath++
63+
}
64+
else {
65+
break
66+
}
67+
}
68+
69+
// if the size of this block is one, we should not enlarge it
70+
if (index == maxIndexWithSamePath - 1) {
71+
index++
72+
continue
73+
}
74+
75+
// otherwise, enlarge the block of shortened names with one new fragment
76+
for (i in index until maxIndexWithSamePath) {
77+
if (!nameInfoCollection[i].enlargeShortName()) {
78+
return collectShortenedNames()
79+
}
80+
}
81+
82+
// after enlarging the block, we proceed to search for the next block
83+
index = maxIndexWithSamePath
84+
}
85+
}
86+
87+
return collectShortenedNames()
88+
}
89+
90+
private fun collectShortenedNames() = nameToInfo.values.mapTo(mutableSetOf()) { it.shortenedName }
91+
92+
}

0 commit comments

Comments
 (0)