From 1c348b928321f799c4880a3615c316a537d4a45a Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 18 May 2017 17:49:48 +0200 Subject: [PATCH] java reparse tests -> community, enlighten --- .../com/intellij/psi/JavaReparseTest.java | 229 ++++++++++++++++++ .../intellij/psi/AbstractReparseTestCase.java | 45 ++-- .../intellij/codeInsight/XmlReparseTest.java | 22 +- 3 files changed, 261 insertions(+), 35 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/psi/JavaReparseTest.java diff --git a/java/java-tests/testSrc/com/intellij/psi/JavaReparseTest.java b/java/java-tests/testSrc/com/intellij/psi/JavaReparseTest.java new file mode 100644 index 000000000000..214d2bcfef47 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/JavaReparseTest.java @@ -0,0 +1,229 @@ +package com.intellij.psi; + +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileTypes.MockLanguageFileType; +import com.intellij.openapi.fileTypes.PlainTextLanguage; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.impl.DebugUtil; +import com.intellij.psi.impl.source.PsiExpressionCodeFragmentImpl; +import com.intellij.psi.impl.source.SourceTreeToPsiMap; +import com.intellij.psi.text.BlockSupport; +import com.intellij.psi.xml.XmlTag; +import com.intellij.psi.xml.XmlText; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.util.IncorrectOperationException; +import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class JavaReparseTest extends AbstractReparseTestCase { + + public void testInsertLBrace() throws Exception { + setFileType(StdFileTypes.JAVA); + final String text2 = "}}}"; + final String text1 = "class Foo{ void method(){{"; + prepareFile(text1, text2); + insert("{"); + } + + public void testJavaDoc() throws Exception { + setFileType(StdFileTypes.JAVA); + String text2 = "void method() {}}"; + final String text1 = "class Foo { /** "; + prepareFile(text1, text2); + insert("*/"); + } + + public void testSCR5665() throws Exception { + setFileType(StdFileTypes.JAVA); + final String text2 = " \"and then insert it again\"}\n" + + " };\n" + + "}"; + final String text1 = "class RedTest {\n" + + " String[][] test = {\n" + + " {\"remove the comma >\","; + prepareFile(text1, text2); + remove(1); + insert(","); + PsiFile file1 = myDummyFile; + prepareFile(text1, text2); + assertEquals(DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(file1), false), + DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(myDummyFile), false)); + } + + + @NotNull + @Override + protected PsiFile createDummyFile(@NotNull String fileName, @NotNull String text) throws IncorrectOperationException { + if (getTestName(true).equals("codeFragment")) return new PsiExpressionCodeFragmentImpl(getProject(), true, "fragment.java", text, null, + null); + return super.createDummyFile(fileName, text); + } + + public void testCodeFragment() throws Exception { + setFileType(StdFileTypes.JAVA); + prepareFile("a", "a"); + insert("xxx xxx xxx xxx xxx xxx xxx"); + } + + public void testReparseAfterReformatReplacesWhitespaceNodesOnly() throws Exception { + @NonNls final String text = + "class RedTest { \n\n\n\n\n\n\n\n " + + "String [ ] [ ] test = { { \n\n\n\n\n { \"\"} \n\n\n\n\n }; " + + "String [ ] [ ] test = { { \n\n\n\n\n { \"\"} \n\n\n\n\n }; " + + " \n\n\n\n\n\n\n\n } "; + + final PsiFile file = myFixture.addFileToProject("aaa.java", text); + final int[] added = {0}; + final int[] removed = {0}; + final int[] replacedWhite = {0}; + final int[] replacedNWhite = {0}; + final int[] moved = {0}; + + file.getManager().addPsiTreeChangeListener(new PsiTreeChangeAdapter() { + @Override + public void childAdded(@NotNull PsiTreeChangeEvent event) { + PsiElement oldElement = event.getChild(); + if (oldElement instanceof PsiWhiteSpace) replacedWhite[0]++; else added[0]++; + } + + @Override + public void childRemoved(@NotNull PsiTreeChangeEvent event) { + PsiElement oldElement = event.getOldChild(); + if (oldElement instanceof PsiWhiteSpace) replacedWhite[0]++; else removed[0]++; + } + + @Override + public void childReplaced(@NotNull PsiTreeChangeEvent event) { + PsiElement oldElement = event.getOldChild(); + PsiElement newElement = event.getNewChild(); + + if (oldElement instanceof PsiWhiteSpace) { + replacedWhite[0]++; + } + else { + replacedNWhite[0]++; + } + if (newElement instanceof PsiWhiteSpace) { + replacedWhite[0]++; + } + else { + replacedNWhite[0]++; + } + } + + @Override + public void childMoved(@NotNull PsiTreeChangeEvent event) { + moved[0]++; + } + }, getProject()); + + WriteCommandAction.runWriteCommandAction(getProject(), () -> { + CodeStyleManager.getInstance(getProject()).reformatText(file, 0, file.getTextLength()); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + }); + + assertEquals(0, added[0]); + assertEquals(0, removed[0]); + assertEquals(0, moved[0]); + assertEquals(0, replacedNWhite[0]); + assertTrue(0 != replacedWhite[0]); + } + + public void testInsertXMLSubTagProducesAddEvents() throws Exception { + @NonNls @Language("XML") + final String text = "\n" + + " \n" + + " TODO\n" + + " \n" + + "\n" + + "\n" + + "\n" + + ""; + + final PsiFile file = myFixture.addFileToProject("aaa.xml", text); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + + final List added = new ArrayList<>(); + final List removed = new ArrayList<>(); + final List replaced = new ArrayList<>(); + final List moved = new ArrayList<>(); + file.getManager().addPsiTreeChangeListener(new PsiTreeChangeAdapter(){ + @Override + public void childAdded(@NotNull PsiTreeChangeEvent event) { + added.add(event.getChild()); + } + + @Override + public void childRemoved(@NotNull PsiTreeChangeEvent event) { + removed.add(event.getElement()); + } + + @Override + public void childReplaced(@NotNull PsiTreeChangeEvent event) { + replaced.add(event.getOldChild()); + } + + @Override + public void childMoved(@NotNull PsiTreeChangeEvent event) { + moved.add(event.getElement()); + } + }, getTestRootDisposable()); + + WriteCommandAction.runWriteCommandAction(getProject(), () -> { + Document document = PsiDocumentManager.getInstance(getProject()).getDocument(file); + int offset = document.getText().indexOf("\n\n") + "\n\n".length(); + document.insertString(offset, ""); + PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); + }); + + assertEquals(2, added.size()); + assertTrue(added.get(0) instanceof XmlTag); + assertEquals("", added.get(0).getText()); + assertTrue(added.get(1) instanceof XmlText); + assertEquals("\n", added.get(1).getText()); + assertEmpty(removed); + assertEmpty(moved); + assertEmpty(replaced); + } + + public void testPlainTextSubstitution() { + LightVirtualFile vFile = new LightVirtualFile("a.xxx", MockLanguageFileType.INSTANCE, "aaa"); + PsiFile file = myDummyFile = PsiManager.getInstance(getProject()).findFile(vFile); + assertNotNull(file); + + assertEquals(com.intellij.lang.Language.ANY, file.getViewProvider().getBaseLanguage()); + assertEquals(PlainTextLanguage.INSTANCE, file.getLanguage()); + assertEquals(file, file.getViewProvider().getPsi(file.getViewProvider().getBaseLanguage())); + + doReparse("b", 0); + assertTrue("baaa", file.isValid()); + assertEquals("baaa", file.getText()); + assertEquals("baaa", file.getFirstChild().getText()); + } + + public void testOverlappingCommonPrefixAndSuffix() { + setFileType(StdFileTypes.JAVA); + String toRemove = "} {foobar"; + prepareFile("class Foo { {goo} {foobar" + toRemove, " foobar} }"); + remove(toRemove.length()); + } + + public void testDocComment() { + String text = "/** .../ */"; + final int offset = text.indexOf("..."); + myDummyFile = createDummyFile(getName() + ".java", text); + String treeBefore = DebugUtil.psiTreeToString(myDummyFile, true); + WriteCommandAction.runWriteCommandAction(getProject(), () -> { + BlockSupport.getInstance(getProject()).reparseRange(myDummyFile, offset, offset + 3, "*"); + BlockSupport.getInstance(getProject()).reparseRange(myDummyFile, offset, offset + 1, "..."); + }); + String treeAfter = DebugUtil.psiTreeToString(myDummyFile, true); + assertEquals(treeBefore, treeAfter); + } +} diff --git a/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java b/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java index 50242f214809..66568bc4d2bb 100644 --- a/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java +++ b/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java @@ -4,17 +4,18 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeRegistry; import com.intellij.psi.impl.DebugUtil; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.text.BlockSupport; -import com.intellij.testFramework.PsiTestCase; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; /** * @author maxim */ -public abstract class AbstractReparseTestCase extends PsiTestCase { +public abstract class AbstractReparseTestCase extends LightCodeInsightFixtureTestCase { protected FileType myFileType; protected PsiFile myDummyFile; private int myInsertOffset; @@ -35,20 +36,11 @@ public abstract class AbstractReparseTestCase extends PsiTestCase { String oldText = myDummyFile.getText(); String expectedNewText = oldText.substring(0, myInsertOffset) + s + oldText.substring(myInsertOffset); - try { - doReparseAndCheck(s, expectedNewText, 0); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } + doReparseAndCheck(s, expectedNewText, 0); myInsertOffset += s.length(); }), "asd", null); } - protected void moveEditPointLeft(int count) { - myInsertOffset -= count; - } - protected void moveEditPointRight(int count) { myInsertOffset += count; } @@ -67,29 +59,24 @@ public abstract class AbstractReparseTestCase extends PsiTestCase { private void doReparseAndCheck(final String s, final String expectedNewText, final int length) throws IncorrectOperationException { doReparse(s, length); - String foundStructure = DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(myDummyFile), false); + String foundStructure = DebugUtil.treeToString(myDummyFile.getNode(), false); final PsiFile psiFile = createDummyFile(getName() + "." + myFileType.getDefaultExtension(), expectedNewText); - String expectedStructure = DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(psiFile), false); - if (!expectedStructure.equals(foundStructure)) { - System.out.println("expected: "); - System.out.println(expectedStructure); - System.out.println("found: "); - System.out.println(foundStructure); - assertEquals(expectedStructure, foundStructure); - } + String expectedStructure = DebugUtil.treeToString(psiFile.getNode(), false); + assertEquals(expectedStructure, foundStructure); assertEquals("Reparse tree should be equal to the document", expectedNewText, myDummyFile.getText()); } + @NotNull + protected PsiFile createDummyFile(@NotNull String fileName, @NotNull String text) throws IncorrectOperationException { + FileType type = FileTypeRegistry.getInstance().getFileTypeByFileName(fileName); + return PsiFileFactory.getInstance(getProject()).createFileFromText(fileName, type, text); + } + protected void doReparse(final String s, final int length) { CommandProcessor.getInstance().executeCommand(getProject(), () -> ApplicationManager.getApplication().runWriteAction(() -> { - BlockSupport blockSupport = ServiceManager.getService(myProject, BlockSupport.class); - try { - blockSupport.reparseRange(myDummyFile, myInsertOffset - length, myInsertOffset, s); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } + BlockSupport blockSupport = ServiceManager.getService(getProject(), BlockSupport.class); + blockSupport.reparseRange(myDummyFile, myInsertOffset - length, myInsertOffset, s); }), "asd", null); } diff --git a/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java b/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java index dbde3480e435..3a149247c6d4 100644 --- a/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java +++ b/xml/tests/src/com/intellij/codeInsight/XmlReparseTest.java @@ -16,7 +16,7 @@ package com.intellij.codeInsight; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.psi.AbstractReparseTestCase; @@ -27,13 +27,11 @@ import com.intellij.psi.impl.DebugUtil; import com.intellij.psi.impl.source.xml.XmlFileImpl; import com.intellij.psi.xml.XmlFile; import com.intellij.testFramework.ParsingTestCase; -import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.IncorrectOperationException; import java.io.File; -@PlatformTestCase.WrapInCommand public class XmlReparseTest extends AbstractReparseTestCase { @Override protected void setUp() throws Exception { @@ -144,7 +142,7 @@ public class XmlReparseTest extends AbstractReparseTestCase { } private static final String marker = ""; public void testXmlDeclDtd() throws Exception { - PsiFile file = createFile("x.xml", "\n" + " \n" + "]>\n" + @@ -160,10 +158,10 @@ public class XmlReparseTest extends AbstractReparseTestCase { ParsingTestCase.doCheckResult(myFullDataPath, file, true, "testXmlDeclDtd", false, false); } - private static void removeGarbage(Document document) { + private void removeGarbage(Document document) { int i = document.getText().indexOf(marker); if (i==-1) return; - ApplicationManager.getApplication().runWriteAction(() -> document.replaceString(i, i + marker.length(), "")); + WriteCommandAction.runWriteCommandAction(getProject(), () -> document.replaceString(i, i + marker.length(), "")); removeGarbage(document); } @@ -172,4 +170,16 @@ public class XmlReparseTest extends AbstractReparseTestCase { protected String getTestDataPath() { return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + "/xml/tests/testData/"; } + + public void testXml() throws Exception{ + setFileType(StdFileTypes.XML); + String text2 = ""; + final String text1 = "/n"; + prepareFile(text1, text2); + insert("<"); + PsiElement element = myDummyFile.findElementAt(10); + assert element != null; + assertNotNull(element.getTextRange()); + } + }