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.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.resolve.TargetPlatform
import java.io.File
@@ -38,9 +39,9 @@ abstract class KotlinFixtureCompletionBaseTestCase : KotlinLightCodeInsightFixtu
open fun doTest(testPath: String) {
setUpFixture(testPath)
val fileText = FileUtil.loadFile(File(testPath), true)
val configured = configureCompilerOptions(fileText, project, module)
try {
val fileText = FileUtil.loadFile(File(testPath), true)
configureCompilerOptions(fileText, project, module)
assertTrue("\"<caret>\" is missing in file \"$testPath\"", fileText.contains("<caret>"))
@@ -57,6 +58,9 @@ abstract class KotlinFixtureCompletionBaseTestCase : KotlinLightCodeInsightFixtu
additionalValidDirectives = CompilerTestDirectives.ALL_COMPILER_TEST_DIRECTIVES
)
} finally {
if (configured) {
rollbackCompilerOptions(project, module)
}
tearDownFixture()
}
}
@@ -32,6 +32,8 @@ import com.intellij.testFramework.LoggedErrorProcessor
import org.apache.log4j.Logger
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
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.LanguageVersion
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)
}
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 jvmTarget = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// $JVM_TARGET_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 }
}
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(
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.highlighter.NameHighlighter;
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.KtFile;
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) {
PsiFile file = getFile();
boolean configured = KotlinLightCodeInsightFixtureTestCaseKt.configureCompilerOptions(file.getText(), getProject(), getModule());
try {
PsiFile file = getFile();
if (file instanceof KtFile && ((KtFile) file).isScript() && myFixture instanceof JavaCodeInsightTestFixtureImpl) {
((JavaCodeInsightTestFixtureImpl) myFixture).canChangeDocumentDuringHighlighting(true);
}
@@ -80,6 +82,10 @@ public abstract class AbstractPsiCheckerTest extends KotlinLightCodeInsightFixtu
}
catch (FileComparisonFailure e) {
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.TestFixtureExtension
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.versions.bundledRuntimeVersion
import org.jetbrains.kotlin.test.InTextDirectivesUtils
@@ -70,7 +71,7 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
val fixtureClasses = InTextDirectivesUtils.findListWithPrefixes(options, "// FIXTURE_CLASS: ")
configureCompilerOptions(options, project, module)
val configured = configureCompilerOptions(options, project, module)
val inspectionsTestDir = optionsFile.parentFile!!
val srcDir = inspectionsTestDir.parentFile!!
@@ -147,6 +148,9 @@ abstract class AbstractInspectionTest : KotlinLightCodeInsightFixtureTestCase()
}
} finally {
if (configured) {
rollbackCompilerOptions(project, module)
}
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.KotlinLightCodeInsightFixtureTestCase
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.psi.KtFile
import org.jetbrains.kotlin.test.InTextDirectivesUtils
@@ -90,35 +91,41 @@ abstract class AbstractLocalInspectionTest : KotlinLightCodeInsightFixtureTestCa
val fileText = FileUtil.loadFile(mainFile, true)
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: ")
if (minJavaVersion != null && !SystemInfo.isJavaVersionAtLeast(minJavaVersion)) return
try {
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")) {
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
}
if (file is KtFile && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// SKIP_ERRORS_BEFORE")) {
DirectiveBasedActionUtils.checkForUnexpectedErrors(file as KtFile)
}
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")) {
DirectiveBasedActionUtils.checkForUnexpectedErrors(file as KtFile)
doTestFor(mainFile.name, inspection, fileText)
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.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.runWriteAction
@@ -200,7 +201,7 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
private fun doTest(beforeFileName: String) {
val mainFile = File(beforeFileName)
val originalFileText = FileUtil.loadFile(mainFile, true)
configureCompilerOptions(originalFileText, project, module)
val configured = configureCompilerOptions(originalFileText, project, module)
val mainFileDir = mainFile.parentFile!!
@@ -266,6 +267,11 @@ abstract class AbstractQuickFixMultiFileTest : KotlinLightCodeInsightFixtureTest
e.printStackTrace()
TestCase.fail(getTestName(true))
}
finally {
if (configured) {
rollbackCompilerOptions(project, module)
}
}
}, "", "")
}
@@ -41,7 +41,7 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase(), Q
@Throws(Exception::class)
protected fun doTest(beforeFileName: String) {
val beforeFileText = FileUtil.loadFile(File(beforeFileName))
configureCompilerOptions(beforeFileText, project, module)
val configured = configureCompilerOptions(beforeFileText, project, module)
val inspections = parseInspectionsToEnable(beforeFileName, beforeFileText).toTypedArray()
@@ -52,6 +52,9 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase(), Q
checkForUnexpectedErrors()
} finally {
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 com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.idea.test.configureCompilerOptions
import org.jetbrains.kotlin.idea.test.rollbackCompilerOptions
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
abstract class AbstractPartialBodyResolveTest : KotlinLightCodeInsightFixtureTestCase() {
@@ -66,74 +67,82 @@ abstract class AbstractPartialBodyResolveTest : KotlinLightCodeInsightFixtureTes
private fun dump(testPath: String, resolveMode: BodyResolveMode): String {
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
val editor = myFixture.editor
val selectionModel = editor.selectionModel
val expression = if (selectionModel.hasSelection()) {
PsiTreeUtil.findElementOfClassAtRange(file, selectionModel.selectionStart, selectionModel.selectionEnd, KtExpression::class.java)
?: 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")
}
try {
val file = myFixture.file as KtFile
val editor = myFixture.editor
val selectionModel = editor.selectionModel
val expression = if (selectionModel.hasSelection()) {
PsiTreeUtil.findElementOfClassAtRange(
file,
selectionModel.selectionStart,
selectionModel.selectionEnd,
KtExpression::class.java
)
?: 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
val (target1, type1, processedStatements1) = doResolve(expression, resolutionFacade.analyze(expression, resolveMode))
// optimized resolve
val (target1, type1, processedStatements1) = doResolve(expression, resolutionFacade.analyze(expression, resolveMode))
// full body resolve
val (target2, type2, processedStatements2) = doResolve(expression, resolutionFacade.analyze(expression))
// full body resolve
val (target2, type2, processedStatements2) = doResolve(expression, resolutionFacade.analyze(expression))
val set = HashSet(processedStatements2)
assert (set.containsAll(processedStatements1))
set.removeAll(processedStatements1)
val set = HashSet(processedStatements2)
assert(set.containsAll(processedStatements1))
set.removeAll(processedStatements1)
val builder = StringBuilder()
val builder = StringBuilder()
if (expression is KtReferenceExpression) {
builder.append("Resolve target: ${target2.presentation(type2)}\n")
}
else {
builder.append("Expression type:${type2.presentation()}\n")
}
builder.append("----------------------------------------------\n")
if (expression is KtReferenceExpression) {
builder.append("Resolve target: ${target2.presentation(type2)}\n")
} else {
builder.append("Expression type:${type2.presentation()}\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
.sortedBy { it.textOffset }
myFixture.project.executeWriteCommand("") {
for (statement in skippedStatements) {
statement.replace(KtPsiFactory(project).createComment("/* STATEMENT DELETED: ${statement.compactPresentation()} */"))
myFixture.project.executeWriteCommand("") {
for (statement in skippedStatements) {
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(