Deduplicate code in AbstractQuickFixMulti{File,Module}Test

This commit is contained in:
Alexander Udalov
2017-09-19 14:18:05 +03:00
parent 113c83b47a
commit 60430828cf
2 changed files with 72 additions and 150 deletions
@@ -17,22 +17,23 @@
package org.jetbrains.kotlin.idea.quickfix package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.CodeInsightSettings import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.quickFix.ActionHint import com.intellij.codeInsight.daemon.quickFix.ActionHint
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInspection.InspectionEP import com.intellij.codeInspection.InspectionEP
import com.intellij.codeInspection.LocalInspectionEP import com.intellij.codeInspection.LocalInspectionEP
import com.intellij.ide.highlighter.JavaFileType import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.fileTypes.FileType import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.PlainTextFileType import com.intellij.openapi.fileTypes.PlainTextFileType
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.openapi.vfs.CharsetToolkit
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.testFramework.VfsTestUtil import com.intellij.psi.PsiFile
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtil
import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.ContainerUtil
@@ -155,7 +156,7 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
DirectiveBasedActionUtils.checkForUnexpectedErrors(psiFile) DirectiveBasedActionUtils.checkForUnexpectedErrors(psiFile)
} }
doAction(text, actionShouldBeAvailable, getTestName(false)) doAction(text, file, editor, actionShouldBeAvailable, getTestName(false), this::availableActions, myFixture::doHighlighting)
val actualText = file.text val actualText = file.text
val afterText = StringBuilder(actualText).insert(editor.caretModel.offset, "<caret>").toString() val afterText = StringBuilder(actualText).insert(editor.caretModel.offset, "<caret>").toString()
@@ -218,7 +219,7 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
DirectiveBasedActionUtils.checkForUnexpectedErrors(psiFile) DirectiveBasedActionUtils.checkForUnexpectedErrors(psiFile)
} }
doAction(text, actionShouldBeAvailable, beforeFileName) doAction(text, file, editor, actionShouldBeAvailable, beforeFileName, this::availableActions, myFixture::doHighlighting)
if (actionShouldBeAvailable) { if (actionShouldBeAvailable) {
val afterFilePath = beforeFileName.replace(".before.Main.", ".after.") val afterFilePath = beforeFileName.replace(".before.Main.", ".after.")
@@ -257,20 +258,52 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
}, "", "") }, "", "")
} }
@Throws(Exception::class) private val availableActions: List<IntentionAction>
fun doAction(text: String, actionShouldBeAvailable: Boolean, testFilePath: String) { get() {
myFixture.doHighlighting()
return myFixture.availableIntentions
}
class TestFile internal constructor(val path: String, val content: String)
companion object {
private fun getActionsTexts(availableActions: List<IntentionAction>): List<String> =
availableActions.map(IntentionAction::getText)
private fun extraFileNamePrefix(mainFileName: String): String =
mainFileName.replace(".Main.kt", ".").replace(".Main.java", ".")
protected fun guessFileType(file: TestFile): FileType = when {
file.path.contains("." + KotlinFileType.EXTENSION) -> KotlinFileType.INSTANCE
file.path.contains("." + JavaFileType.DEFAULT_EXTENSION) -> JavaFileType.INSTANCE
else -> PlainTextFileType.INSTANCE
}
private fun findActionByPattern(pattern: Pattern, availableActions: List<IntentionAction>): IntentionAction? =
availableActions.firstOrNull { pattern.matcher(it.text).matches() }
fun doAction(
text: String,
file: PsiFile,
editor: Editor,
actionShouldBeAvailable: Boolean,
testFilePath: String,
getAvailableActions: () -> List<IntentionAction>,
doHighlighting: () -> List<HighlightInfo>,
shouldBeAvailableAfterExecution: Boolean = false
) {
val pattern = if (text.startsWith("/")) val pattern = if (text.startsWith("/"))
Pattern.compile(text.substring(1, text.length - 1)) Pattern.compile(text.substring(1, text.length - 1))
else else
Pattern.compile(StringUtil.escapeToRegexp(text)) Pattern.compile(StringUtil.escapeToRegexp(text))
val availableActions = availableActions val availableActions = getAvailableActions()
val action = findActionByPattern(pattern, availableActions) val action = findActionByPattern(pattern, availableActions)
if (action == null) { if (action == null) {
if (actionShouldBeAvailable) { if (actionShouldBeAvailable) {
val texts = getActionsTexts(availableActions) val texts = getActionsTexts(availableActions)
val infos = myFixture.doHighlighting() val infos = doHighlighting()
TestCase.fail("Action with text '" + text + "' is not available in test " + testFilePath + "\n" + TestCase.fail("Action with text '" + text + "' is not available in test " + testFilePath + "\n" +
"Available actions (" + texts.size + "): \n" + "Available actions (" + texts.size + "): \n" +
StringUtil.join(texts, "\n") + StringUtil.join(texts, "\n") +
@@ -290,8 +323,8 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
CodeInsightTestFixtureImpl.invokeIntention(action, file, editor, action.text) CodeInsightTestFixtureImpl.invokeIntention(action, file, editor, action.text)
if (!shouldBeAvailableAfterExecution()) { if (!shouldBeAvailableAfterExecution) {
val afterAction = findActionByPattern(pattern, this.availableActions) val afterAction = findActionByPattern(pattern, getAvailableActions())
if (afterAction != null) { if (afterAction != null) {
TestCase.fail("Action '$text' is still available after its invocation in test $testFilePath") TestCase.fail("Action '$text' is still available after its invocation in test $testFilePath")
@@ -299,53 +332,5 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
} }
} }
} }
private val availableActions: List<IntentionAction>
get() {
myFixture.doHighlighting()
return myFixture.availableIntentions
}
class TestFile internal constructor(val path: String, val content: String)
companion object {
protected fun shouldBeAvailableAfterExecution(): Boolean {
return false
}
private fun getActionsTexts(availableActions: List<IntentionAction>): List<String> {
val texts = ArrayList<String>()
for (intentionAction in availableActions) {
texts.add(intentionAction.text)
}
return texts
}
private fun extraFileNamePrefix(mainFileName: String): String {
return mainFileName.replace(".Main.kt", ".").replace(".Main.java", ".")
}
protected fun guessFileType(file: TestFile): FileType {
if (file.path.contains("." + KotlinFileType.EXTENSION)) {
return KotlinFileType.INSTANCE
}
else if (file.path.contains("." + JavaFileType.DEFAULT_EXTENSION)) {
return JavaFileType.INSTANCE
}
else {
return PlainTextFileType.INSTANCE
}
}
private fun findActionByPattern(pattern: Pattern, availableActions: List<IntentionAction>): IntentionAction? {
for (availableAction in availableActions) {
if (pattern.matcher(availableAction.text).matches()) {
return availableAction
}
}
return null
}
} }
} }
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.daemon.quickFix.ActionHint import com.intellij.codeInsight.daemon.quickFix.ActionHint
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler
import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.util.text.StringUtil
import com.intellij.util.ui.UIUtil
import junit.framework.ComparisonFailure import junit.framework.ComparisonFailure
import junit.framework.TestCase import junit.framework.TestCase
import org.jetbrains.kotlin.idea.inspections.findExistingEditor import org.jetbrains.kotlin.idea.inspections.findExistingEditor
@@ -34,17 +31,11 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File import java.io.File
import java.util.regex.Pattern
abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() { abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() + "/multiModuleQuickFix/" override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() + "/multiModuleQuickFix/"
protected fun shouldBeAvailableAfterExecution(file: KtFile) =
InTextDirectivesUtils.isDirectiveDefined(file.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION")
private fun getActionsTexts(availableActions: List<IntentionAction>) = availableActions.map { it.text }
protected fun doQuickFixTest() { protected fun doQuickFixTest() {
val allFilesInProject = PluginJetFilesProvider.allFilesInProject(myProject!!) val allFilesInProject = PluginJetFilesProvider.allFilesInProject(myProject!!)
val actionFile = allFilesInProject.single { file -> val actionFile = allFilesInProject.single { file ->
@@ -58,18 +49,19 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
CommandProcessor.getInstance().executeCommand(project, { CommandProcessor.getInstance().executeCommand(project, {
try { try {
val psiFile = actionFile val actionHint = ActionHint.parse(actionFile, actionFileText)
val actionHint = ActionHint.parse(psiFile, actionFileText)
val text = actionHint.expectedText val text = actionHint.expectedText
val actionShouldBeAvailable = actionHint.shouldPresent() val actionShouldBeAvailable = actionHint.shouldPresent()
if (psiFile is KtFile) { if (actionFile is KtFile) {
DirectiveBasedActionUtils.checkForUnexpectedErrors(psiFile) DirectiveBasedActionUtils.checkForUnexpectedErrors(actionFile)
} }
doAction(text, actionShouldBeAvailable, actionFileName, actionFile) AbstractQuickFixMultiFileTest.doAction(
text, file, editor, actionShouldBeAvailable, actionFileName, this::availableActions, this::doHighlighting,
InTextDirectivesUtils.isDirectiveDefined(actionFile.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION")
)
if (actionShouldBeAvailable) { if (actionShouldBeAvailable) {
val testDirectory = File(testDataPath) val testDirectory = File(testDataPath)
@@ -106,63 +98,8 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest() {
}, "", "") }, "", "")
} }
// TODO: merge with AbstractQuickFixMultiFileTest private val availableActions: List<IntentionAction>
get() {
fun doAction(text: String, actionShouldBeAvailable: Boolean, testFilePath: String, actionFile: KtFile) {
val pattern = if (text.startsWith("/"))
Pattern.compile(text.substring(1, text.length - 1))
else
Pattern.compile(StringUtil.escapeToRegexp(text))
val availableActions = getAvailableActions()
val action = findActionByPattern(pattern, availableActions)
if (action == null) {
if (actionShouldBeAvailable) {
val texts = getActionsTexts(availableActions)
val infos = doHighlighting()
TestCase.fail("Action with text '" + text + "' is not available in test " + testFilePath + "\n" +
"Available actions (" + texts.size + "): \n" +
StringUtil.join(texts, "\n") +
"\nActions:\n" +
StringUtil.join(availableActions, "\n") +
"\nInfos:\n" +
StringUtil.join(infos, "\n"))
}
else {
DirectiveBasedActionUtils.checkAvailableActionsAreExpected(file, availableActions)
}
}
else {
if (!actionShouldBeAvailable) {
TestCase.fail("Action '$text' is available (but must not) in test $testFilePath")
}
ShowIntentionActionsHandler.chooseActionAndInvoke(file, editor, action, action.text)
UIUtil.dispatchAllInvocationEvents()
if (!shouldBeAvailableAfterExecution(actionFile)) {
val afterAction = findActionByPattern(pattern, getAvailableActions())
if (afterAction != null) {
TestCase.fail("Action '$text' is still available after its invocation in test $testFilePath")
}
}
}
}
private fun findActionByPattern(pattern: Pattern, availableActions: List<IntentionAction>): IntentionAction? {
for (availableAction in availableActions) {
if (pattern.matcher(availableAction.text).matches()) {
return availableAction
}
}
return null
}
private fun getAvailableActions(): List<IntentionAction> {
doHighlighting() doHighlighting()
return LightQuickFixTestCase.getAvailableActions(editor, file) return LightQuickFixTestCase.getAvailableActions(editor, file)
} }