Rollback language / API version at the end of IDE tests

This should fix some flaky tests
This commit is contained in:
Mikhail Glukhikh
2018-10-19 16:35:13 +03:00
parent 0eb5934e09
commit 784d9f14f6
8 changed files with 143 additions and 85 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.caches.project.LibraryModificationTracker
import org.jetbrains.kotlin.idea.test.CompilerTestDirectives import org.jetbrains.kotlin.idea.test.CompilerTestDirectives
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.configureCompilerOptions import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import java.io.File import java.io.File
@@ -38,9 +39,9 @@ abstract class KotlinFixtureCompletionBaseTestCase : KotlinLightCodeInsightFixtu
open fun doTest(testPath: String) { open fun doTest(testPath: String) {
setUpFixture(testPath) setUpFixture(testPath)
val fileText = FileUtil.loadFile(File(testPath), true)
val configured = configureCompilerOptions(fileText, project, module)
try { try {
val fileText = FileUtil.loadFile(File(testPath), true)
configureCompilerOptions(fileText, project, module)
assertTrue("\"<caret>\" is missing in file \"$testPath\"", fileText.contains("<caret>")) assertTrue("\"<caret>\" is missing in file \"$testPath\"", fileText.contains("<caret>"))
@@ -57,6 +58,9 @@ abstract class KotlinFixtureCompletionBaseTestCase : KotlinLightCodeInsightFixtu
additionalValidDirectives = CompilerTestDirectives.ALL_COMPILER_TEST_DIRECTIVES additionalValidDirectives = CompilerTestDirectives.ALL_COMPILER_TEST_DIRECTIVES
) )
} finally { } finally {
if (configured) {
rollbackCompilerOptions(project, module)
}
tearDownFixture() tearDownFixture()
} }
} }
@@ -32,6 +32,8 @@ import com.intellij.testFramework.LoggedErrorProcessor
import org.apache.log4j.Logger import org.apache.log4j.Logger
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.config.CompilerSettings import org.jetbrains.kotlin.config.CompilerSettings
import org.jetbrains.kotlin.config.CompilerSettings.Companion.DEFAULT_ADDITIONAL_ARGUMENTS
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
@@ -207,7 +209,7 @@ object CompilerTestDirectives {
val ALL_COMPILER_TEST_DIRECTIVES = listOf(LANGUAGE_VERSION_DIRECTIVE, JVM_TARGET_DIRECTIVE, COMPILER_ARGUMENTS_DIRECTIVE) val ALL_COMPILER_TEST_DIRECTIVES = listOf(LANGUAGE_VERSION_DIRECTIVE, JVM_TARGET_DIRECTIVE, COMPILER_ARGUMENTS_DIRECTIVE)
} }
fun configureCompilerOptions(fileText: String, project: Project, module: Module) { fun configureCompilerOptions(fileText: String, project: Project, module: Module): Boolean {
val version = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $LANGUAGE_VERSION_DIRECTIVE ") val version = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $LANGUAGE_VERSION_DIRECTIVE ")
val jvmTarget = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $JVM_TARGET_DIRECTIVE ") val jvmTarget = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $JVM_TARGET_DIRECTIVE ")
val options = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $COMPILER_ARGUMENTS_DIRECTIVE ") val options = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $COMPILER_ARGUMENTS_DIRECTIVE ")
@@ -230,7 +232,24 @@ fun configureCompilerOptions(fileText: String, project: Project, module: Module)
KotlinCompilerSettings.getInstance(project).update { this.additionalArguments = options } KotlinCompilerSettings.getInstance(project).update { this.additionalArguments = options }
} }
return true
} }
return false
}
fun rollbackCompilerOptions(project: Project, module: Module) {
configureLanguageAndApiVersion(project, module, LanguageVersion.LATEST_STABLE.versionString)
val facetSettings = KotlinFacet.get(module)!!.configuration.settings
(facetSettings.compilerArguments as K2JVMCompilerArguments).jvmTarget = JvmTarget.DEFAULT.description
val compilerSettings = facetSettings.compilerSettings ?: CompilerSettings().also {
facetSettings.compilerSettings = it
}
compilerSettings.additionalArguments = DEFAULT_ADDITIONAL_ARGUMENTS
facetSettings.updateMergedArguments()
KotlinCompilerSettings.getInstance(project).update { this.additionalArguments = DEFAULT_ADDITIONAL_ARGUMENTS }
} }
fun configureLanguageAndApiVersion( fun configureLanguageAndApiVersion(
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils; import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.highlighter.NameHighlighter; import org.jetbrains.kotlin.idea.highlighter.NameHighlighter;
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase; import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase;
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCaseKt;
import org.jetbrains.kotlin.psi.KtDeclaration; import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid; import org.jetbrains.kotlin.psi.KtTreeVisitorVoid;
@@ -71,8 +72,9 @@ public abstract class AbstractPsiCheckerTest extends KotlinLightCodeInsightFixtu
} }
protected long checkHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings) { protected long checkHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings) {
PsiFile file = getFile();
boolean configured = KotlinLightCodeInsightFixtureTestCaseKt.configureCompilerOptions(file.getText(), getProject(), getModule());
try { try {
PsiFile file = getFile();
if (file instanceof KtFile && ((KtFile) file).isScript() && myFixture instanceof JavaCodeInsightTestFixtureImpl) { if (file instanceof KtFile && ((KtFile) file).isScript() && myFixture instanceof JavaCodeInsightTestFixtureImpl) {
((JavaCodeInsightTestFixtureImpl) myFixture).canChangeDocumentDuringHighlighting(true); ((JavaCodeInsightTestFixtureImpl) myFixture).canChangeDocumentDuringHighlighting(true);
} }
@@ -80,6 +82,10 @@ public abstract class AbstractPsiCheckerTest extends KotlinLightCodeInsightFixtu
} }
catch (FileComparisonFailure e) { catch (FileComparisonFailure e) {
throw new FileComparisonFailure(e.getMessage(), e.getExpected(), e.getActual(), new File(e.getFilePath()).getAbsolutePath()); throw new FileComparisonFailure(e.getMessage(), e.getExpected(), e.getActual(), new File(e.getFilePath()).getAbsolutePath());
} finally {
if (configured) {
KotlinLightCodeInsightFixtureTestCaseKt.rollbackCompilerOptions(getProject(), getModule());
}
} }
} }
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.inspections.runInspection
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.TestFixtureExtension import org.jetbrains.kotlin.idea.test.TestFixtureExtension
import org.jetbrains.kotlin.idea.test.configureCompilerOptions import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
@@ -70,7 +71,7 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
val fixtureClasses = InTextDirectivesUtils.findListWithPrefixes(options, "// FIXTURE_CLASS: ") val fixtureClasses = InTextDirectivesUtils.findListWithPrefixes(options, "// FIXTURE_CLASS: ")
configureCompilerOptions(options, project, module) val configured = configureCompilerOptions(options, project, module)
val inspectionsTestDir = optionsFile.parentFile!! val inspectionsTestDir = optionsFile.parentFile!!
val srcDir = inspectionsTestDir.parentFile!! val srcDir = inspectionsTestDir.parentFile!!
@@ -147,6 +148,9 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
} }
} finally { } finally {
if (configured) {
rollbackCompilerOptions(project, module)
}
fixtureClasses.forEach { TestFixtureExtension.unloadFixture(it) } fixtureClasses.forEach { TestFixtureExtension.unloadFixture(it) }
} }
} }
@@ -31,6 +31,7 @@ import junit.framework.TestCase
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.configureCompilerOptions import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
@@ -90,35 +91,41 @@ abstract class AbstractLocalInspectionTest : KotlinLightCodeInsightFixtureTestCa
val fileText = FileUtil.loadFile(mainFile, true) val fileText = FileUtil.loadFile(mainFile, true)
TestCase.assertTrue("\"<caret>\" is missing in file \"$mainFile\"", fileText.contains("<caret>")) TestCase.assertTrue("\"<caret>\" is missing in file \"$mainFile\"", fileText.contains("<caret>"))
configureCompilerOptions(fileText, project, module) val configured = configureCompilerOptions(fileText, project, module)
val minJavaVersion = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MIN_JAVA_VERSION: ") try {
if (minJavaVersion != null && !SystemInfo.isJavaVersionAtLeast(minJavaVersion)) return val minJavaVersion = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MIN_JAVA_VERSION: ")
if (minJavaVersion != null && !SystemInfo.isJavaVersionAtLeast(minJavaVersion)) return
if (file is KtFile && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// SKIP_ERRORS_BEFORE")) { if (file is KtFile && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// SKIP_ERRORS_BEFORE")) {
DirectiveBasedActionUtils.checkForUnexpectedErrors(file as KtFile) DirectiveBasedActionUtils.checkForUnexpectedErrors(file as KtFile)
}
var i = 1
val extraFileNames = mutableListOf<String>()
extraFileLoop@ while (true) {
for (extension in EXTENSIONS) {
val extraFile = File(mainFile.parent, FileUtil.getNameWithoutExtension(mainFile) + "." + i + extension)
if (extraFile.exists()) {
extraFileNames += extraFile.name
i++
continue@extraFileLoop
}
} }
break
}
myFixture.configureByFiles(*(listOf(mainFile.name) + extraFileNames).toTypedArray()).first() var i = 1
val extraFileNames = mutableListOf<String>()
extraFileLoop@ while (true) {
for (extension in EXTENSIONS) {
val extraFile = File(mainFile.parent, FileUtil.getNameWithoutExtension(mainFile) + "." + i + extension)
if (extraFile.exists()) {
extraFileNames += extraFile.name
i++
continue@extraFileLoop
}
}
break
}
doTestFor(mainFile.name, inspection, fileText) myFixture.configureByFiles(*(listOf(mainFile.name) + extraFileNames).toTypedArray()).first()
if (file is KtFile && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// SKIP_ERRORS_AFTER")) { doTestFor(mainFile.name, inspection, fileText)
DirectiveBasedActionUtils.checkForUnexpectedErrors(file as KtFile)
if (file is KtFile && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// SKIP_ERRORS_AFTER")) {
DirectiveBasedActionUtils.checkForUnexpectedErrors(file as KtFile)
}
} finally {
if (configured) {
rollbackCompilerOptions(project, module)
}
} }
} }
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile
import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.configureCompilerOptions import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.runWriteAction import org.jetbrains.kotlin.test.testFramework.runWriteAction
@@ -200,7 +201,7 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
private fun doTest(beforeFileName: String) { private fun doTest(beforeFileName: String) {
val mainFile = File(beforeFileName) val mainFile = File(beforeFileName)
val originalFileText = FileUtil.loadFile(mainFile, true) val originalFileText = FileUtil.loadFile(mainFile, true)
configureCompilerOptions(originalFileText, project, module) val configured = configureCompilerOptions(originalFileText, project, module)
val mainFileDir = mainFile.parentFile!! val mainFileDir = mainFile.parentFile!!
@@ -266,6 +267,11 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
e.printStackTrace() e.printStackTrace()
TestCase.fail(getTestName(true)) TestCase.fail(getTestName(true))
} }
finally {
if (configured) {
rollbackCompilerOptions(project, module)
}
}
}, "", "") }, "", "")
} }
@@ -41,7 +41,7 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase(), Q
@Throws(Exception::class) @Throws(Exception::class)
protected fun doTest(beforeFileName: String) { protected fun doTest(beforeFileName: String) {
val beforeFileText = FileUtil.loadFile(File(beforeFileName)) val beforeFileText = FileUtil.loadFile(File(beforeFileName))
configureCompilerOptions(beforeFileText, project, module) val configured = configureCompilerOptions(beforeFileText, project, module)
val inspections = parseInspectionsToEnable(beforeFileName, beforeFileText).toTypedArray() val inspections = parseInspectionsToEnable(beforeFileName, beforeFileText).toTypedArray()
@@ -52,6 +52,9 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase(), Q
checkForUnexpectedErrors() checkForUnexpectedErrors()
} finally { } finally {
myFixture.disableInspections(*inspections) myFixture.disableInspections(*inspections)
if (configured) {
rollbackCompilerOptions(project, module)
}
} }
} }
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.idea.test.configureCompilerOptions import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
abstract class AbstractPartialBodyResolveTest : KotlinLightCodeInsightFixtureTestCase() { abstract class AbstractPartialBodyResolveTest : KotlinLightCodeInsightFixtureTestCase() {
@@ -66,74 +67,82 @@ abstract class AbstractPartialBodyResolveTest : KotlinLightCodeInsightFixtureTes
private fun dump(testPath: String, resolveMode: BodyResolveMode): String { private fun dump(testPath: String, resolveMode: BodyResolveMode): String {
myFixture.configureByText(KotlinFileType.INSTANCE, File(testPath).readText()) myFixture.configureByText(KotlinFileType.INSTANCE, File(testPath).readText())
configureCompilerOptions(myFixture.file.text, project, module) val configured = configureCompilerOptions(myFixture.file.text, project, module)
val file = myFixture.file as KtFile try {
val editor = myFixture.editor val file = myFixture.file as KtFile
val selectionModel = editor.selectionModel val editor = myFixture.editor
val expression = if (selectionModel.hasSelection()) { val selectionModel = editor.selectionModel
PsiTreeUtil.findElementOfClassAtRange(file, selectionModel.selectionStart, selectionModel.selectionEnd, KtExpression::class.java) val expression = if (selectionModel.hasSelection()) {
?: error("No JetExpression at selection range") PsiTreeUtil.findElementOfClassAtRange(
} file,
else { selectionModel.selectionStart,
val offset = editor.caretModel.offset selectionModel.selectionEnd,
val element = file.findElementAt(offset)!! KtExpression::class.java
element.getNonStrictParentOfType<KtSimpleNameExpression>() ?: error("No JetSimpleNameExpression at caret") )
} ?: error("No JetExpression at selection range")
} else {
val offset = editor.caretModel.offset
val element = file.findElementAt(offset)!!
element.getNonStrictParentOfType<KtSimpleNameExpression>() ?: error("No JetSimpleNameExpression at caret")
}
val resolutionFacade = file.getResolutionFacade() val resolutionFacade = file.getResolutionFacade()
// optimized resolve // optimized resolve
val (target1, type1, processedStatements1) = doResolve(expression, resolutionFacade.analyze(expression, resolveMode)) val (target1, type1, processedStatements1) = doResolve(expression, resolutionFacade.analyze(expression, resolveMode))
// full body resolve // full body resolve
val (target2, type2, processedStatements2) = doResolve(expression, resolutionFacade.analyze(expression)) val (target2, type2, processedStatements2) = doResolve(expression, resolutionFacade.analyze(expression))
val set = HashSet(processedStatements2) val set = HashSet(processedStatements2)
assert (set.containsAll(processedStatements1)) assert(set.containsAll(processedStatements1))
set.removeAll(processedStatements1) set.removeAll(processedStatements1)
val builder = StringBuilder() val builder = StringBuilder()
if (expression is KtReferenceExpression) { if (expression is KtReferenceExpression) {
builder.append("Resolve target: ${target2.presentation(type2)}\n") builder.append("Resolve target: ${target2.presentation(type2)}\n")
} } else {
else { builder.append("Expression type:${type2.presentation()}\n")
builder.append("Expression type:${type2.presentation()}\n") }
} builder.append("----------------------------------------------\n")
builder.append("----------------------------------------------\n")
val skippedStatements = set val skippedStatements = set
.filter { !it.parents.any { it in set } } // do not include skipped statements which are inside other skipped statement .filter { !it.parents.any { it in set } } // do not include skipped statements which are inside other skipped statement
.sortedBy { it.textOffset } .sortedBy { it.textOffset }
myFixture.project.executeWriteCommand("") { myFixture.project.executeWriteCommand("") {
for (statement in skippedStatements) { for (statement in skippedStatements) {
statement.replace(KtPsiFactory(project).createComment("/* STATEMENT DELETED: ${statement.compactPresentation()} */")) statement.replace(KtPsiFactory(project).createComment("/* STATEMENT DELETED: ${statement.compactPresentation()} */"))
}
}
val fileText = file.text
if (selectionModel.hasSelection()) {
val start = selectionModel.selectionStart
val end = selectionModel.selectionEnd
builder.append(fileText.substring(0, start))
builder.append("<selection>")
builder.append(fileText.substring(start, end))
builder.append("<selection>")
builder.append(fileText.substring(end))
} else {
val newCaretOffset = editor.caretModel.offset
builder.append(fileText.substring(0, newCaretOffset))
builder.append("<caret>")
builder.append(fileText.substring(newCaretOffset))
}
Assert.assertEquals(target2.presentation(null), target1.presentation(null))
Assert.assertEquals(type2.presentation(), type1.presentation())
return builder.toString()
} finally {
if (configured) {
rollbackCompilerOptions(project, module)
} }
} }
val fileText = file.text
if (selectionModel.hasSelection()) {
val start = selectionModel.selectionStart
val end = selectionModel.selectionEnd
builder.append(fileText.substring(0, start))
builder.append("<selection>")
builder.append(fileText.substring(start, end))
builder.append("<selection>")
builder.append(fileText.substring(end))
}
else {
val newCaretOffset = editor.caretModel.offset
builder.append(fileText.substring(0, newCaretOffset))
builder.append("<caret>")
builder.append(fileText.substring(newCaretOffset))
}
Assert.assertEquals(target2.presentation(null), target1.presentation(null))
Assert.assertEquals(type2.presentation(), type1.presentation())
return builder.toString()
} }
private data class ResolveData( private data class ResolveData(