Kotlinify AbstractOutOfBlockModificationTest, p2
This commit is contained in:
+107
-106
@@ -3,121 +3,122 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* 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.codeInsight;
|
package org.jetbrains.kotlin.idea.codeInsight
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
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.psi.PsiDocumentManager;
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiManager
|
||||||
import com.intellij.psi.PsiManager;
|
import com.intellij.psi.impl.PsiModificationTrackerImpl
|
||||||
import com.intellij.psi.impl.PsiModificationTrackerImpl;
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListenerKt;
|
import org.jetbrains.kotlin.idea.caches.trackers.outOfBlockModificationCount
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
|
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase;
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession;
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public abstract class AbstractOutOfBlockModificationTest extends KotlinLightCodeInsightFixtureTestCase {
|
|
||||||
|
|
||||||
public static final String OUT_OF_CODE_BLOCK_DIRECTIVE = "OUT_OF_CODE_BLOCK:";
|
|
||||||
public static final String SKIP_ANALYZE_CHECK_DIRECTIVE = "SKIP_ANALYZE_CHECK";
|
|
||||||
public static final String TYPE_DIRECTIVE = "TYPE:";
|
|
||||||
|
|
||||||
protected void doTest(String unused) throws IOException {
|
|
||||||
myFixture.configureByFile(fileName());
|
|
||||||
|
|
||||||
boolean expectedOutOfBlock = getExpectedOutOfBlockResult();
|
|
||||||
boolean isSkipCheckDefined = InTextDirectivesUtils.isDirectiveDefined(myFixture.getFile().getText(), SKIP_ANALYZE_CHECK_DIRECTIVE);
|
|
||||||
|
|
||||||
assertTrue("It's allowed to skip check with analyze only for tests where out-of-block is expected",
|
|
||||||
!isSkipCheckDefined || expectedOutOfBlock);
|
|
||||||
|
|
||||||
|
|
||||||
PsiModificationTrackerImpl tracker =
|
|
||||||
(PsiModificationTrackerImpl) PsiManager.getInstance(myFixture.getProject()).getModificationTracker();
|
|
||||||
|
|
||||||
PsiElement element = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
|
|
||||||
assertNotNull("Should be valid element", element);
|
|
||||||
|
|
||||||
KtFile file = (KtFile) getFile();
|
|
||||||
|
|
||||||
long oobBeforeType = KotlinCodeBlockModificationListenerKt.getOutOfBlockModificationCount(file);
|
|
||||||
long modificationCountBeforeType = tracker.getModificationCount();
|
|
||||||
|
|
||||||
myFixture.type(getStringToType());
|
|
||||||
PsiDocumentManager.getInstance(myFixture.getProject()).commitDocument(myFixture.getDocument(myFixture.getFile()));
|
|
||||||
|
|
||||||
long oobAfterCount = KotlinCodeBlockModificationListenerKt.getOutOfBlockModificationCount(file);
|
|
||||||
long modificationCountAfterType = tracker.getModificationCount();
|
|
||||||
|
|
||||||
assertTrue("Modification tracker should always be changed after type", modificationCountBeforeType != modificationCountAfterType);
|
|
||||||
|
|
||||||
assertEquals("Result for out of block test is differs from expected on element in file:\n"
|
|
||||||
+ FileUtil.loadFile(testDataFile()),
|
|
||||||
expectedOutOfBlock, oobBeforeType != oobAfterCount);
|
|
||||||
|
|
||||||
|
abstract class AbstractOutOfBlockModificationTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||||
|
protected fun doTest(unused: String?) {
|
||||||
|
val ktFile = myFixture.configureByFile(fileName()) as KtFile
|
||||||
|
val expectedOutOfBlock = expectedOutOfBlockResult
|
||||||
|
val isSkipCheckDefined = InTextDirectivesUtils.isDirectiveDefined(
|
||||||
|
ktFile.text,
|
||||||
|
SKIP_ANALYZE_CHECK_DIRECTIVE
|
||||||
|
)
|
||||||
|
TestCase.assertTrue(
|
||||||
|
"It's allowed to skip check with analyze only for tests where out-of-block is expected",
|
||||||
|
!isSkipCheckDefined || expectedOutOfBlock
|
||||||
|
)
|
||||||
|
val tracker =
|
||||||
|
PsiManager.getInstance(myFixture.project).modificationTracker as PsiModificationTrackerImpl
|
||||||
|
val element = ktFile.findElementAt(myFixture.caretOffset)
|
||||||
|
TestCase.assertNotNull("Should be valid element", element)
|
||||||
|
val oobBeforeType = ktFile.outOfBlockModificationCount
|
||||||
|
val modificationCountBeforeType = tracker.modificationCount
|
||||||
|
myFixture.type(stringToType)
|
||||||
|
PsiDocumentManager.getInstance(myFixture.project).commitDocument(myFixture.getDocument(myFixture.file))
|
||||||
|
val oobAfterCount = ktFile.outOfBlockModificationCount
|
||||||
|
val modificationCountAfterType = tracker.modificationCount
|
||||||
|
TestCase.assertTrue(
|
||||||
|
"Modification tracker should always be changed after type",
|
||||||
|
modificationCountBeforeType != modificationCountAfterType
|
||||||
|
)
|
||||||
|
TestCase.assertEquals(
|
||||||
|
"Result for out of block test is differs from expected on element in file:\n"
|
||||||
|
+ FileUtil.loadFile(testDataFile()),
|
||||||
|
expectedOutOfBlock, oobBeforeType != oobAfterCount
|
||||||
|
)
|
||||||
if (!isSkipCheckDefined) {
|
if (!isSkipCheckDefined) {
|
||||||
checkOOBWithDescriptorsResolve(expectedOutOfBlock);
|
checkOOBWithDescriptorsResolve(expectedOutOfBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkOOBWithDescriptorsResolve(boolean expectedOutOfBlock) {
|
private fun checkOOBWithDescriptorsResolve(expectedOutOfBlock: Boolean) {
|
||||||
ApplicationManager.getApplication().runReadAction(
|
ApplicationManager.getApplication().runReadAction {
|
||||||
() -> ((PsiModificationTrackerImpl) PsiManager.getInstance(myFixture.getProject()).getModificationTracker())
|
(PsiManager.getInstance(myFixture.project).modificationTracker as PsiModificationTrackerImpl)
|
||||||
.incOutOfCodeBlockModificationCounter());
|
.incOutOfCodeBlockModificationCounter()
|
||||||
|
|
||||||
PsiElement updateElement = myFixture.getFile().findElementAt(myFixture.getCaretOffset() - 1);
|
|
||||||
KtExpression ktExpression = PsiTreeUtil.getParentOfType(updateElement, KtExpression.class, false);
|
|
||||||
KtDeclaration ktDeclaration = PsiTreeUtil.getParentOfType(updateElement, KtDeclaration.class, false);
|
|
||||||
KtElement ktElement = ktExpression != null ? ktExpression : ktDeclaration;
|
|
||||||
|
|
||||||
if (ktElement == null) return;
|
|
||||||
|
|
||||||
ResolutionFacade facade = ResolutionUtils.getResolutionFacade(ktElement.getContainingKtFile());
|
|
||||||
ResolveSession session = facade.getFrontendService(ResolveSession.class);
|
|
||||||
session.forceResolveAll();
|
|
||||||
|
|
||||||
BindingContext context = session.getBindingContext();
|
|
||||||
|
|
||||||
if (ktExpression != null && ktExpression != ktDeclaration) {
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
boolean expressionProcessed = context.get(
|
|
||||||
BindingContext.PROCESSED,
|
|
||||||
ktExpression instanceof KtFunctionLiteral ? (KtLambdaExpression) ktExpression.getParent() : ktExpression) == Boolean.TRUE;
|
|
||||||
|
|
||||||
assertEquals("Expected out-of-block should result expression analyzed and vise versa", expectedOutOfBlock,
|
|
||||||
expressionProcessed);
|
|
||||||
}
|
}
|
||||||
else {
|
val updateElement = myFixture.file.findElementAt(myFixture.caretOffset - 1)
|
||||||
boolean declarationProcessed = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, ktDeclaration) != null;
|
val ktExpression: KtExpression? = PsiTreeUtil.getParentOfType(updateElement, KtExpression::class.java, false)
|
||||||
assertEquals("Expected out-of-block should result declaration analyzed and vise versa", expectedOutOfBlock,
|
val ktDeclaration: KtDeclaration? = PsiTreeUtil.getParentOfType(updateElement, KtDeclaration::class.java, false)
|
||||||
declarationProcessed);
|
val ktElement = ktExpression ?: ktDeclaration ?: return
|
||||||
|
val facade = ktElement.containingKtFile.getResolutionFacade()
|
||||||
|
val session = facade.getFrontendService(ResolveSession::class.java)
|
||||||
|
session.forceResolveAll()
|
||||||
|
val context = session.bindingContext
|
||||||
|
if (ktExpression != null && ktExpression !== ktDeclaration) {
|
||||||
|
val expressionProcessed = context.get(
|
||||||
|
BindingContext.PROCESSED,
|
||||||
|
if (ktExpression is KtFunctionLiteral) ktExpression.getParent() as KtLambdaExpression else ktExpression
|
||||||
|
) === java.lang.Boolean.TRUE
|
||||||
|
TestCase.assertEquals(
|
||||||
|
"Expected out-of-block should result expression analyzed and vise versa", expectedOutOfBlock,
|
||||||
|
expressionProcessed
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val declarationProcessed =
|
||||||
|
context.get(
|
||||||
|
BindingContext.DECLARATION_TO_DESCRIPTOR,
|
||||||
|
ktDeclaration
|
||||||
|
) != null
|
||||||
|
TestCase.assertEquals(
|
||||||
|
"Expected out-of-block should result declaration analyzed and vise versa", expectedOutOfBlock,
|
||||||
|
declarationProcessed
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getStringToType() {
|
private val stringToType: String
|
||||||
String text = myFixture.getDocument(myFixture.getFile()).getText();
|
get() {
|
||||||
String typeDirectives = InTextDirectivesUtils.findStringWithPrefixes(text, TYPE_DIRECTIVE);
|
val text = myFixture.getDocument(myFixture.file).text
|
||||||
|
val typeDirectives =
|
||||||
|
InTextDirectivesUtils.findStringWithPrefixes(text, TYPE_DIRECTIVE)
|
||||||
|
return if (typeDirectives != null) StringUtil.unescapeStringCharacters(typeDirectives) else "a"
|
||||||
|
}
|
||||||
|
|
||||||
return typeDirectives != null ? StringUtil.unescapeStringCharacters(typeDirectives) : "a";
|
private val expectedOutOfBlockResult: Boolean
|
||||||
|
get() {
|
||||||
|
val text = myFixture.getDocument(myFixture.file).text
|
||||||
|
val outOfCodeBlockDirective = InTextDirectivesUtils.findStringWithPrefixes(
|
||||||
|
text,
|
||||||
|
OUT_OF_CODE_BLOCK_DIRECTIVE
|
||||||
|
)
|
||||||
|
assertNotNull(
|
||||||
|
"${fileName()}: Expectation of code block result test should be configured with " +
|
||||||
|
"\"// " + OUT_OF_CODE_BLOCK_DIRECTIVE + " TRUE\" or " +
|
||||||
|
"\"// " + OUT_OF_CODE_BLOCK_DIRECTIVE + " FALSE\" directive in the file",
|
||||||
|
outOfCodeBlockDirective
|
||||||
|
)
|
||||||
|
return outOfCodeBlockDirective?.toBoolean() ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val OUT_OF_CODE_BLOCK_DIRECTIVE = "OUT_OF_CODE_BLOCK:"
|
||||||
|
const val SKIP_ANALYZE_CHECK_DIRECTIVE = "SKIP_ANALYZE_CHECK"
|
||||||
|
const val TYPE_DIRECTIVE = "TYPE:"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private boolean getExpectedOutOfBlockResult() {
|
|
||||||
String text = myFixture.getDocument(myFixture.getFile()).getText();
|
|
||||||
|
|
||||||
String outOfCodeBlockDirective = InTextDirectivesUtils.findStringWithPrefixes(text, OUT_OF_CODE_BLOCK_DIRECTIVE);
|
|
||||||
assertNotNull(fileName() +
|
|
||||||
": Expectation of code block result test should be configured with " +
|
|
||||||
"\"// " + OUT_OF_CODE_BLOCK_DIRECTIVE + " TRUE\" or " +
|
|
||||||
"\"// " + OUT_OF_CODE_BLOCK_DIRECTIVE + " FALSE\" directive in the file",
|
|
||||||
outOfCodeBlockDirective);
|
|
||||||
return Boolean.parseBoolean(outOfCodeBlockDirective);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user