Validate new file or class name for empty parts (KT-27903)

#KT-27903 Fixed
This commit is contained in:
Nikolay Krasko
2018-11-01 12:11:24 +03:00
parent 0e7520fde3
commit 9978ba4aaa
2 changed files with 93 additions and 2 deletions
@@ -35,9 +35,11 @@ import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.ui.InputValidatorEx
import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.util.IncorrectOperationException import com.intellij.util.IncorrectOperationException
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinIcons import org.jetbrains.kotlin.idea.KotlinIcons
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -86,6 +88,8 @@ class NewKotlinFileAction : CreateFileFromTemplateAction(
.addKind("Interface", KotlinIcons.INTERFACE, "Kotlin Interface") .addKind("Interface", KotlinIcons.INTERFACE, "Kotlin Interface")
.addKind("Enum class", KotlinIcons.ENUM, "Kotlin Enum") .addKind("Enum class", KotlinIcons.ENUM, "Kotlin Enum")
.addKind("Object", KotlinIcons.OBJECT, "Kotlin Object") .addKind("Object", KotlinIcons.OBJECT, "Kotlin Object")
builder.setValidator(NameValidator)
} }
override fun getActionName(directory: PsiDirectory, newName: String, templateName: String) = "Kotlin File/Class" override fun getActionName(directory: PsiDirectory, newName: String, templateName: String) = "Kotlin File/Class"
@@ -114,7 +118,34 @@ class NewKotlinFileAction : CreateFileFromTemplateAction(
Companion.createFileFromTemplate(name, template, dir) Companion.createFileFromTemplate(name, template, dir)
companion object { companion object {
private fun findOrCreateTarget(dir: PsiDirectory, name: String, directorySeparators: Array<Char>): Pair<String, PsiDirectory> { private object NameValidator : InputValidatorEx {
override fun getErrorText(inputString: String): String? {
if (inputString.trim().isEmpty()) {
return "Name can't be empty"
}
val parts: List<String> = inputString.split(*FQNAME_SEPARATORS)
if (parts.any { it.trim().isEmpty() }) {
return "Name can't have empty parts"
}
return null
}
override fun checkInput(inputString: String): Boolean {
return true
}
override fun canClose(inputString: String): Boolean {
return getErrorText(inputString) == null
}
}
@get:TestOnly
val nameValidator: InputValidatorEx
get() = NameValidator
private fun findOrCreateTarget(dir: PsiDirectory, name: String, directorySeparators: CharArray): Pair<String, PsiDirectory> {
var className = name.substringBeforeLast(".kt") var className = name.substringBeforeLast(".kt")
var targetDir = dir var targetDir = dir
@@ -157,8 +188,11 @@ class NewKotlinFileAction : CreateFileFromTemplateAction(
return element?.containingFile return element?.containingFile
} }
private val FILE_SEPARATORS = charArrayOf('/', '\\')
private val FQNAME_SEPARATORS = charArrayOf('/', '\\', '.')
fun createFileFromTemplate(name: String, template: FileTemplate, dir: PsiDirectory): PsiFile? { fun createFileFromTemplate(name: String, template: FileTemplate, dir: PsiDirectory): PsiFile? {
val directorySeparators = if (template.name == "Kotlin File") arrayOf('/', '\\') else arrayOf('/', '\\', '.') val directorySeparators = if (template.name == "Kotlin File") FILE_SEPARATORS else FQNAME_SEPARATORS
val (className, targetDir) = findOrCreateTarget(dir, name, directorySeparators) val (className, targetDir) = findOrCreateTarget(dir, name, directorySeparators)
val service = DumbService.getInstance(dir.project) val service = DumbService.getInstance(dir.project)
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.actions
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.junit.Assert
class NewKotlinFileActionTest: LightCodeInsightFixtureTestCase() {
companion object {
private val EMPTY_PARTS_ERROR = "Name can't have empty parts"
private val EMPTY_ERROR = "Name can't be empty"
}
fun testEmptyName() {
validateName("", EMPTY_ERROR)
}
fun testSpaces() {
validateName(" ", EMPTY_ERROR)
}
fun testEmptyEnd() {
validateName("Foo/", EMPTY_PARTS_ERROR)
}
fun testEmptyPartInQualified() {
validateName("a..b", EMPTY_PARTS_ERROR)
}
fun testFileWithKt() {
validateName("test.kt", null)
}
fun testFileWithUnixPathKt() {
validateName("a/b/test.kt", null)
}
fun testFileWithWinPathKt() {
validateName("a\\b\\test.kt", null)
}
fun testSimpleFile() {
validateName("some", null)
}
fun testSimpleFileWithPath() {
validateName("a/bb\\some", null)
}
private fun validateName(name: String, errorMessage: String?) {
val actualError = NewKotlinFileAction.nameValidator.getErrorText(name)
Assert.assertEquals("Invalid error message", errorMessage, actualError)
}
}