172: Revert "Update file name replace in QuickFix tests"
This reverts commit 01051618aa21c3502463c699f1d178136ef7c6b6.
This commit is contained in:
@@ -0,0 +1,266 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.quickFix.ActionHint
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
|
import com.intellij.codeInspection.InspectionProfileEntry
|
||||||
|
import com.intellij.codeInspection.LocalInspectionTool
|
||||||
|
import com.intellij.codeInspection.SuppressableProblemGroup
|
||||||
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import com.intellij.openapi.vfs.CharsetToolkit
|
||||||
|
import com.intellij.rt.execution.junit.FileComparisonFailure
|
||||||
|
import com.intellij.testFramework.*
|
||||||
|
import com.intellij.util.ui.UIUtil
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile
|
||||||
|
import org.jetbrains.kotlin.idea.test.*
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
|
import org.junit.Assert
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||||
|
@Throws(Exception::class)
|
||||||
|
protected fun doTest(beforeFileName: String) {
|
||||||
|
val beforeFileText = FileUtil.loadFile(File(beforeFileName))
|
||||||
|
configureCompilerOptions(beforeFileText, project, module)
|
||||||
|
|
||||||
|
val inspections = parceInspectionsToEnable(beforeFileName, beforeFileText).toTypedArray()
|
||||||
|
|
||||||
|
try {
|
||||||
|
myFixture.enableInspections(*inspections)
|
||||||
|
|
||||||
|
doKotlinQuickFixTest(beforeFileName)
|
||||||
|
checkForUnexpectedErrors()
|
||||||
|
} finally {
|
||||||
|
myFixture.disableInspections(*inspections)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getProjectDescriptor(): LightProjectDescriptor {
|
||||||
|
if ("createfromusage" in testDataPath.toLowerCase()) {
|
||||||
|
return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||||
|
}
|
||||||
|
return super.getProjectDescriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val captureExceptions: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
fun shouldBeAvailableAfterExecution(): Boolean {
|
||||||
|
return InTextDirectivesUtils.isDirectiveDefined(myFixture.file.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun configExtra(options: String) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPathAccordingToPackage(name: String, text: String): String {
|
||||||
|
val packagePath = text.lines().let { it.find { it.trim().startsWith("package") } }
|
||||||
|
?.removePrefix("package")
|
||||||
|
?.trim()?.replace(".", "/") ?: ""
|
||||||
|
return packagePath + "/" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doKotlinQuickFixTest(beforeFileName: String) {
|
||||||
|
val testFile = File(beforeFileName)
|
||||||
|
CommandProcessor.getInstance().executeCommand(project, {
|
||||||
|
var fileText = ""
|
||||||
|
var expectedErrorMessage: String? = ""
|
||||||
|
var fixtureClasses = emptyList<String>()
|
||||||
|
try {
|
||||||
|
fileText = FileUtil.loadFile(testFile, CharsetToolkit.UTF8_CHARSET)
|
||||||
|
TestCase.assertTrue("\"<caret>\" is missing in file \"${testFile.path}\"", fileText.contains("<caret>"))
|
||||||
|
|
||||||
|
fixtureClasses = InTextDirectivesUtils.findListWithPrefixes(fileText, "// FIXTURE_CLASS: ")
|
||||||
|
for (fixtureClass in fixtureClasses) {
|
||||||
|
TestFixtureExtension.loadFixture(fixtureClass, LightPlatformTestCase.getModule())
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedErrorMessage = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// SHOULD_FAIL_WITH: ")
|
||||||
|
val contents = StringUtil.convertLineSeparators(fileText)
|
||||||
|
var filePath = testFile.canonicalFile.name
|
||||||
|
val putIntoPackageFolder = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// FORCE_PACKAGE_FOLDER") != null
|
||||||
|
if (putIntoPackageFolder) {
|
||||||
|
filePath = getPathAccordingToPackage(filePath, contents)
|
||||||
|
myFixture.addFileToProject(filePath, contents)
|
||||||
|
myFixture.configureByFile(filePath)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
myFixture.configureByText(filePath, contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUnexpectedActions()
|
||||||
|
|
||||||
|
configExtra(fileText)
|
||||||
|
|
||||||
|
applyAction(contents, filePath)
|
||||||
|
|
||||||
|
UsefulTestCase.assertEmpty(expectedErrorMessage)
|
||||||
|
}
|
||||||
|
catch (e: FileComparisonFailure) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
catch (e: AssertionError) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
if (expectedErrorMessage == null) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Assert.assertEquals("Wrong exception message", expectedErrorMessage, e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
for (fixtureClass in fixtureClasses) {
|
||||||
|
TestFixtureExtension.unloadFixture(fixtureClass)
|
||||||
|
}
|
||||||
|
ConfigLibraryUtil.unconfigureLibrariesByDirective(myFixture.module, fileText)
|
||||||
|
}
|
||||||
|
}, "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyAction(contents: String, testFullPath: String) {
|
||||||
|
val fileName = testFullPath.substringAfterLast(File.separatorChar, "")
|
||||||
|
val actionHint = ActionHint.parse(myFixture.file, contents.replace("\${file}", fileName, ignoreCase = true))
|
||||||
|
val intention = findActionWithText(actionHint.expectedText)
|
||||||
|
if (actionHint.shouldPresent()) {
|
||||||
|
if (intention == null) {
|
||||||
|
fail("Action with text '" + actionHint.expectedText + "' not found\nAvailable actions: " +
|
||||||
|
myFixture.availableIntentions.joinToString(prefix = "[", postfix = "]") { it.text })
|
||||||
|
}
|
||||||
|
myFixture.launchAction(intention!!)
|
||||||
|
UIUtil.dispatchAllInvocationEvents()
|
||||||
|
UIUtil.dispatchAllInvocationEvents()
|
||||||
|
|
||||||
|
if (!shouldBeAvailableAfterExecution()) {
|
||||||
|
assertNull("Action '${actionHint.expectedText}' is still available after its invocation in test " + testFullPath,
|
||||||
|
findActionWithText(actionHint.expectedText))
|
||||||
|
}
|
||||||
|
|
||||||
|
myFixture.checkResultByFile(File(testFullPath).name + ".after")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertNull("Action with text ${actionHint.expectedText} is present, but should not", intention)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parceInspectionsToEnable(beforeFileName: String, beforeFileText: String): List<InspectionProfileEntry> {
|
||||||
|
val toolsStrings = InTextDirectivesUtils.findListWithPrefixes(beforeFileText, "TOOL:")
|
||||||
|
if (toolsStrings.isNotEmpty()) {
|
||||||
|
val inspections = toolsStrings.map { toolFqName ->
|
||||||
|
try {
|
||||||
|
val aClass = Class.forName(toolFqName)
|
||||||
|
return@map aClass.newInstance() as LocalInspectionTool
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
throw IllegalArgumentException("Failed to create inspection for key '$toolFqName'", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inspections
|
||||||
|
}
|
||||||
|
|
||||||
|
val inspectionFile = findInspectionFile(File(beforeFileName).parentFile)
|
||||||
|
if (inspectionFile != null) {
|
||||||
|
val className = FileUtil.loadFile(inspectionFile).trim { it <= ' ' }
|
||||||
|
val inspectionClass = Class.forName(className) as Class<InspectionProfileEntry>
|
||||||
|
return InspectionTestUtil.instantiateTools(listOf<Class<out InspectionProfileEntry>>(inspectionClass))
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ClassNotFoundException::class)
|
||||||
|
private fun checkForUnexpectedActions() {
|
||||||
|
val text = myFixture.editor.document.text
|
||||||
|
val actionHint = ActionHint.parse(myFixture.file, text)
|
||||||
|
if (!actionHint.shouldPresent()) {
|
||||||
|
val actions = myFixture.availableIntentions
|
||||||
|
|
||||||
|
val prefix = "class "
|
||||||
|
if (actionHint.expectedText.startsWith(prefix)) {
|
||||||
|
val className = actionHint.expectedText.substring(prefix.length)
|
||||||
|
val aClass = Class.forName(className)
|
||||||
|
assert(IntentionAction::class.java.isAssignableFrom(aClass)) { className + " should be inheritor of IntentionAction" }
|
||||||
|
|
||||||
|
val validActions = HashSet(InTextDirectivesUtils.findLinesWithPrefixesRemoved(text, "// ACTION:"))
|
||||||
|
|
||||||
|
actions.removeAll { action -> !aClass.isAssignableFrom(action.javaClass) || validActions.contains(action.text) }
|
||||||
|
|
||||||
|
if (!actions.isEmpty()) {
|
||||||
|
Assert.fail("Unexpected intention actions present\n " + actions.map { action -> action.javaClass.toString() + " " + action.toString() + "\n" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (action in actions) {
|
||||||
|
if (aClass.isAssignableFrom(action.javaClass) && !validActions.contains(action.text)) {
|
||||||
|
Assert.fail("Unexpected intention action " + action.javaClass + " found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Action shouldn't be found. Check that other actions are expected and thus tested action isn't there under another name.
|
||||||
|
DirectiveBasedActionUtils.checkAvailableActionsAreExpected(myFixture.file, actions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findActionWithText(text: String): IntentionAction? {
|
||||||
|
val intentions = myFixture.availableIntentions.filter { it.text == text }
|
||||||
|
if (intentions.isNotEmpty()) return intentions.first()
|
||||||
|
|
||||||
|
// Support warning suppression
|
||||||
|
val caretOffset = myFixture.caretOffset
|
||||||
|
for (highlight in myFixture.doHighlighting()) {
|
||||||
|
if (highlight.startOffset <= caretOffset && caretOffset <= highlight.endOffset) {
|
||||||
|
val group = highlight.problemGroup
|
||||||
|
if (group is SuppressableProblemGroup) {
|
||||||
|
val at = myFixture.file.findElementAt(highlight.actualStartOffset)
|
||||||
|
val actions = group.getSuppressActions(at)
|
||||||
|
for (action in actions) {
|
||||||
|
if (action.text == text) {
|
||||||
|
return action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkForUnexpectedErrors() {
|
||||||
|
DirectiveBasedActionUtils.checkForUnexpectedErrors(myFixture.file as KtFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTestDataPath(): String {
|
||||||
|
// Ensure full path is returned. Otherwise FileComparisonFailureException does not provide link to file diff
|
||||||
|
val testDataPath = super.getTestDataPath()
|
||||||
|
try {
|
||||||
|
return File(testDataPath).getCanonicalPath()
|
||||||
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
return testDataPath
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user