Add intention to replace snake-case test function name with a space-separated
#KT-27143 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
5226ea5cda
commit
98810ba750
@@ -1381,6 +1381,11 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.ConvertSnakeCaseTestFunctionToSpacedIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetIntention</className>
|
||||
<category>Kotlin</category>
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class MyTest {
|
||||
@Test fun <spot>`test two plus two equals four`</spot>() {
|
||||
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class MyTest {
|
||||
@Test fun <spot>test_two_plus_two_equals_four</spot>() {
|
||||
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention changes a snake case name of the given test function to a space-separated one.
|
||||
</body>
|
||||
</html>
|
||||
+79
-50
@@ -37,16 +37,29 @@ import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
class ConvertCamelCaseTestFunctionToSpacedIntention : SelfTargetingRangeIntention<KtNamedFunction>(
|
||||
KtNamedFunction::class.java, "Replace camel-case name with spaces"
|
||||
sealed class ConvertTestFunctionToSpacedIntention(case: String) : SelfTargetingRangeIntention<KtNamedFunction>(
|
||||
KtNamedFunction::class.java, "Replace $case name with spaces"
|
||||
) {
|
||||
companion object {
|
||||
private val SNAKE_CASE_REGEX = ".+_.+".toRegex()
|
||||
}
|
||||
|
||||
abstract fun split(name: String): List<String>
|
||||
|
||||
abstract fun isApplicableName(name: String): Boolean
|
||||
|
||||
protected fun isSnakeCase(name: String): Boolean {
|
||||
return name.contains(SNAKE_CASE_REGEX)
|
||||
}
|
||||
|
||||
override fun applicabilityRange(element: KtNamedFunction): TextRange? {
|
||||
val platform = element.platform
|
||||
if (platform is CommonPlatform || platform is JsPlatform) return null
|
||||
val range = element.nameIdentifier?.textRange ?: return null
|
||||
|
||||
val name = element.name ?: return null
|
||||
val newName = decamelize(name)
|
||||
if (!isApplicableName(name)) return null
|
||||
val newName = convert(name)
|
||||
if (newName == name.quoteIfNeeded()) return null
|
||||
|
||||
val lightMethod = element.toLightMethods().firstOrNull() ?: return null
|
||||
@@ -57,11 +70,67 @@ class ConvertCamelCaseTestFunctionToSpacedIntention : SelfTargetingRangeIntentio
|
||||
return range
|
||||
}
|
||||
|
||||
private fun convert(name: String) = split(name).joinToString(separator = " ") { it.decapitalizeSmart().trim() }.quoteIfNeeded()
|
||||
|
||||
private fun startRename(element: KtNamedFunction, newName: String) {
|
||||
RenameProcessor(element.project, element, newName, false, false).run()
|
||||
}
|
||||
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
override fun applyTo(element: KtNamedFunction, editor: Editor?) {
|
||||
val nameIdentifier = element.nameIdentifier ?: return
|
||||
val oldName = element.name ?: return
|
||||
val oldId = oldName.quoteIfNeeded()
|
||||
val newId = convert(oldName)
|
||||
|
||||
if (editor != null) {
|
||||
val builder = TemplateBuilderImpl(nameIdentifier)
|
||||
builder.replaceElement(nameIdentifier, newId)
|
||||
val template = runWriteAction { builder.buildInlineTemplate() }
|
||||
TemplateManager.getInstance(element.project).startTemplate(
|
||||
editor,
|
||||
template,
|
||||
object : TemplateEditingAdapter() {
|
||||
private var chosenId: String = newId
|
||||
private var range: TextRange? = null
|
||||
|
||||
override fun beforeTemplateFinished(state: TemplateState, template: Template?) {
|
||||
val varName = (template as? TemplateImpl)?.getVariableNameAt(0) ?: return
|
||||
chosenId = state.getVariableValue(varName)?.text?.quoteIfNeeded() ?: return
|
||||
range = state.getVariableRange(varName)
|
||||
}
|
||||
|
||||
override fun templateFinished(template: Template, brokenOff: Boolean) {
|
||||
range?.let {
|
||||
val doc = editor.document
|
||||
runWriteAction { doc.replaceString(it.startOffset, it.endOffset, oldId) }
|
||||
PsiDocumentManager.getInstance(element.project).commitDocument(doc)
|
||||
}
|
||||
|
||||
if (!brokenOff && chosenId != oldId) {
|
||||
startRename(element, chosenId)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
startRename(element, newId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ConvertCamelCaseTestFunctionToSpacedIntention : ConvertTestFunctionToSpacedIntention("camel-case") {
|
||||
override fun isApplicableName(name: String): Boolean {
|
||||
return !isSnakeCase(name)
|
||||
}
|
||||
|
||||
enum class Case {
|
||||
LOWER, UPPER, OTHER
|
||||
}
|
||||
|
||||
private fun splitCamelName(name: String): List<String> {
|
||||
override fun split(name: String): List<String> {
|
||||
if (name === "") return emptyList()
|
||||
|
||||
val result = SmartList<String>()
|
||||
@@ -88,54 +157,14 @@ class ConvertCamelCaseTestFunctionToSpacedIntention : SelfTargetingRangeIntentio
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private fun decamelize(name: String) = splitCamelName(name).joinToString(separator = " ") { it.decapitalizeSmart().trim() }.quoteIfNeeded()
|
||||
|
||||
private fun startRename(element: KtNamedFunction, newName: String) {
|
||||
RenameProcessor(element.project, element, newName, false, false).run()
|
||||
class ConvertSnakeCaseTestFunctionToSpacedIntention : ConvertTestFunctionToSpacedIntention("snake_case") {
|
||||
override fun isApplicableName(name: String): Boolean {
|
||||
return isSnakeCase(name)
|
||||
}
|
||||
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
override fun applyTo(element: KtNamedFunction, editor: Editor?) {
|
||||
val nameIdentifier = element.nameIdentifier ?: return
|
||||
val oldName = element.name ?: return
|
||||
val oldId = oldName.quoteIfNeeded()
|
||||
val newId = decamelize(oldName)
|
||||
|
||||
if (editor != null) {
|
||||
val builder = TemplateBuilderImpl(nameIdentifier)
|
||||
builder.replaceElement(nameIdentifier, newId)
|
||||
val template = runWriteAction { builder.buildInlineTemplate() }
|
||||
TemplateManager.getInstance(element.project).startTemplate(
|
||||
editor,
|
||||
template,
|
||||
object : TemplateEditingAdapter() {
|
||||
private var chosenId: String = newId
|
||||
private var range: TextRange? = null
|
||||
|
||||
override fun beforeTemplateFinished(state: TemplateState, template: Template?) {
|
||||
val varName = (template as? TemplateImpl)?.getVariableNameAt(0) ?: return
|
||||
chosenId = state?.getVariableValue(varName)?.text?.quoteIfNeeded() ?: return
|
||||
range = state.getVariableRange(varName)
|
||||
}
|
||||
|
||||
override fun templateFinished(template: Template, brokenOff: Boolean) {
|
||||
range?.let {
|
||||
val doc = editor.document
|
||||
runWriteAction { doc.replaceString(it.startOffset, it.endOffset, oldId) }
|
||||
PsiDocumentManager.getInstance(element.project).commitDocument(doc)
|
||||
}
|
||||
|
||||
if (!brokenOff && chosenId != oldId) {
|
||||
startRename(element, chosenId)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
else {
|
||||
startRename(element, newId)
|
||||
}
|
||||
override fun split(name: String): List<String> {
|
||||
return name.split("_").filter { it.isNotBlank() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
class A {
|
||||
@Test fun <caret>test_two_plus_two_equals_four() {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
A().test_two_plus_two_equals_four()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.ConvertSnakeCaseTestFunctionToSpacedIntention
|
||||
@@ -0,0 +1,8 @@
|
||||
// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar
|
||||
// IS_APPLICABLE: false
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
class A {
|
||||
@Test fun <caret>testTwoPlusTwoEqualsFour() {}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar
|
||||
import org.junit.Test
|
||||
|
||||
class A {
|
||||
@Test fun <caret>test_two_plus_two_equals_four() {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
A().test_two_plus_two_equals_four()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar
|
||||
import org.junit.Test
|
||||
|
||||
class A {
|
||||
@Test fun `test two plus two equals four`() {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
A().`test two plus two equals four`()
|
||||
}
|
||||
@@ -4804,6 +4804,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
runTest("idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/notTestFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("snake.kt")
|
||||
public void testSnake() throws Exception {
|
||||
runTest("idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/snake.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unchanged.kt")
|
||||
public void testUnchanged() throws Exception {
|
||||
runTest("idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/unchanged.kt");
|
||||
@@ -7014,6 +7019,29 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ConvertSnakeCaseTestFunctionToSpaced extends AbstractIntentionTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInConvertSnakeCaseTestFunctionToSpaced() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("camel.kt")
|
||||
public void testCamel() throws Exception {
|
||||
runTest("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/camel.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("snake.kt")
|
||||
public void testSnake() throws Exception {
|
||||
runTest("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/convertToAlso")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user