| /* |
| * Copyright 2000-2014 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 com.intellij.psi; |
| |
| import com.intellij.ide.highlighter.JavaFileType; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.editor.Document; |
| import com.intellij.openapi.editor.SelectionModel; |
| import com.intellij.openapi.fileEditor.FileDocumentManager; |
| import com.intellij.openapi.fileEditor.FileEditorManager; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.impl.PsiManagerEx; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.psi.util.PsiModificationTracker; |
| import com.intellij.testFramework.IdeaTestCase; |
| import com.intellij.testFramework.PlatformTestUtil; |
| import com.intellij.testFramework.SkipSlowTestLocally; |
| import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; |
| import com.intellij.util.Processor; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.NonNls; |
| |
| import java.io.IOException; |
| |
| /** |
| * @author Dmitry Avdeev |
| */ |
| @SkipSlowTestLocally |
| public class PsiModificationTrackerTest extends LightPlatformCodeInsightFixtureTestCase { |
| @Override |
| public void setUp() throws Exception { |
| IdeaTestCase.initPlatformPrefix(); |
| super.setUp(); |
| } |
| |
| public void testAnnotationNotChanged() throws Exception { |
| doReplaceTest("@SuppressWarnings(\"zz\")\n" + |
| "public class Foo { <selection></selection>}", |
| "hi"); |
| } |
| |
| public void testAnnotationNameChanged() throws Exception { |
| doReplaceTest("@Suppr<selection>ess</selection>Warnings(\"zz\")\n" + |
| "public class Foo { }", |
| "hi"); |
| } |
| |
| public void testAnnotationParameterChanged() throws Exception { |
| doReplaceTest("@SuppressWarnings(\"<selection>zz</selection>\")\n" + |
| "public class Foo { }", |
| "hi"); |
| } |
| |
| public void testAnnotationRemoved() throws Exception { |
| doReplaceTest("<selection>@SuppressWarnings(\"zz\")</selection>\n" + |
| "public class Foo { }", |
| ""); |
| } |
| |
| public void testAnnotationWithClassRemoved() throws Exception { |
| doReplaceTest("<selection>@SuppressWarnings(\"zz\")\n" + |
| "public </selection> class Foo { }", |
| ""); |
| } |
| |
| public void testRemoveAnnotatedMethod() throws Exception { |
| doReplaceTest("public class Foo {\n" + |
| " <selection> " + |
| " @SuppressWarnings(\"\")\n" + |
| " public void method() {}\n" + |
| "</selection>" + |
| "}", |
| ""); |
| } |
| |
| public void testRenameAnnotatedMethod() throws Exception { |
| doReplaceTest("public class Foo {\n" + |
| " @SuppressWarnings(\"\")\n" + |
| " public void me<selection>th</selection>od() {}\n" + |
| "}", |
| "zzz"); |
| } |
| |
| public void testRenameAnnotatedClass() throws Exception { |
| doReplaceTest(" @SuppressWarnings(\"\")\n" + |
| "public class F<selection>o</selection>o {\n" + |
| " public void method() {}\n" + |
| "}", |
| "zzz"); |
| } |
| |
| public void testRemoveAll() throws Exception { |
| doReplaceTest("<selection>@SuppressWarnings(\"zz\")\n" + |
| "public class Foo { }</selection>", |
| ""); |
| } |
| |
| public void testRemoveFile() throws Exception { |
| doTest("<selection>@SuppressWarnings(\"zz\")\n" + |
| "public class Foo { }</selection>", |
| new Processor<PsiFile>() { |
| @Override |
| public boolean process(PsiFile psiFile) { |
| try { |
| final VirtualFile vFile = psiFile.getVirtualFile(); |
| assert vFile != null : psiFile; |
| FileEditorManager.getInstance(getProject()).closeFile(vFile); |
| vFile.delete(this); |
| } |
| catch (IOException e) { |
| fail(e.getMessage()); |
| } |
| return false; |
| } |
| }); |
| } |
| |
| private void doReplaceTest(@NonNls String text, @NonNls final String with) { |
| doTest(text, new Processor<PsiFile>() { |
| @Override |
| public boolean process(PsiFile psiFile) { |
| replaceSelection(with); |
| return false; |
| } |
| }); |
| } |
| |
| private void doTest(@NonNls String text, Processor<PsiFile> run) { |
| PsiFile file = myFixture.configureByText(JavaFileType.INSTANCE, text); |
| PsiModificationTracker modificationTracker = PsiManager.getInstance(getProject()).getModificationTracker(); |
| long count = modificationTracker.getModificationCount(); |
| run.process(file); |
| assertFalse(modificationTracker.getModificationCount() == count); |
| } |
| |
| private void replaceSelection(final String with) { |
| new WriteCommandAction.Simple(getProject()) { |
| @Override |
| protected void run() throws Throwable { |
| SelectionModel sel = myFixture.getEditor().getSelectionModel(); |
| myFixture.getEditor().getDocument().replaceString(sel.getSelectionStart(), sel.getSelectionEnd(), with); |
| PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); |
| } |
| }.execute(); |
| } |
| |
| public void testJavaStructureModificationChangesAfterPackageDelete() { |
| PsiFile file = myFixture.addFileToProject("/x/y/Z.java", "text"); |
| PsiModificationTracker modificationTracker = PsiManager.getInstance(getProject()).getModificationTracker(); |
| long count = modificationTracker.getJavaStructureModificationCount(); |
| |
| file.getContainingDirectory().delete(); |
| |
| assertEquals(count + 1, modificationTracker.getJavaStructureModificationCount()); |
| } |
| |
| public void testClassShouldNotAppearWithoutEvents_WithPsi() throws IOException { |
| final VirtualFile file = myFixture.getTempDirFixture().createFile("Foo.java", ""); |
| final Document document = FileDocumentManager.getInstance().getDocument(file); |
| assertNotNull(document); |
| new WriteCommandAction.Simple(getProject()) { |
| @Override |
| protected void run() throws Throwable { |
| assertNull(JavaPsiFacade.getInstance(getProject()).findClass("Foo", GlobalSearchScope.allScope(getProject()))); |
| PsiManager psiManager = PsiManager.getInstance(getProject()); |
| PsiModificationTracker tracker = psiManager.getModificationTracker(); |
| long count1 = tracker.getJavaStructureModificationCount(); |
| PsiJavaFile psiFile = (PsiJavaFile)psiManager.findFile(file); |
| |
| document.insertString(0, "class Foo {}"); |
| |
| assertEquals(count1, tracker.getJavaStructureModificationCount()); // no PSI changes yet |
| //so the class should not exist |
| assertNull(JavaPsiFacade.getInstance(getProject()).findClass("Foo", GlobalSearchScope.allScope(getProject()))); |
| assertSize(0, psiFile.getClasses()); |
| assertEquals("", psiManager.findFile(file).getText()); |
| PlatformTestUtil.tryGcSoftlyReachableObjects(); |
| |
| PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); |
| |
| assertFalse(count1 == tracker.getJavaStructureModificationCount()); |
| assertNotNull(JavaPsiFacade.getInstance(getProject()).findClass("Foo", GlobalSearchScope.allScope(getProject()))); |
| assertEquals("class Foo {}", psiManager.findFile(file).getText()); |
| assertEquals("class Foo {}", psiManager.findFile(file).getNode().getText()); |
| assertSize(1, psiFile.getClasses()); |
| } |
| }.execute(); |
| } |
| |
| public void testClassShouldNotAppearWithoutEvents_WithoutPsi() throws IOException { |
| final GlobalSearchScope allScope = GlobalSearchScope.allScope(getProject()); |
| final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); |
| final PsiManager psiManager = PsiManager.getInstance(getProject()); |
| final PsiModificationTracker tracker = psiManager.getModificationTracker(); |
| |
| final VirtualFile file = myFixture.getTempDirFixture().createFile("Foo.java", ""); |
| final Document document = FileDocumentManager.getInstance().getDocument(file); |
| assertNotNull(document); |
| new WriteCommandAction.Simple(getProject()) { |
| @Override |
| protected void run() throws Throwable { |
| assertNull(facade.findClass("Foo", allScope)); |
| long count1 = tracker.getJavaStructureModificationCount(); |
| |
| PlatformTestUtil.tryGcSoftlyReachableObjects(); |
| assertNull(PsiDocumentManager.getInstance(getProject()).getCachedPsiFile(document)); |
| |
| document.insertString(0, "class Foo {}"); |
| |
| assertFalse(count1 == tracker.getJavaStructureModificationCount()); |
| assertTrue(PsiDocumentManager.getInstance(getProject()).isCommitted(document)); |
| assertNotNull(facade.findClass("Foo", allScope)); |
| |
| PsiJavaFile psiFile = (PsiJavaFile)psiManager.findFile(file); |
| assertSize(1, psiFile.getClasses()); |
| assertEquals("class Foo {}", psiFile.getText()); |
| assertEquals("class Foo {}", psiFile.getNode().getText()); |
| } |
| }.execute(); |
| } |
| |
| public void testClassShouldNotDisappearWithoutEvents() throws IOException { |
| new WriteCommandAction.Simple(getProject()) { |
| @Override |
| protected void run() throws Throwable { |
| PsiModificationTracker tracker = PsiManager.getInstance(getProject()).getModificationTracker(); |
| long count0 = tracker.getJavaStructureModificationCount(); |
| |
| final VirtualFile file = myFixture.addFileToProject("Foo.java", "class Foo {}").getVirtualFile(); |
| final Document document = FileDocumentManager.getInstance().getDocument(file); |
| assertNotNull(document); |
| |
| assertNotNull(JavaPsiFacade.getInstance(getProject()).findClass("Foo", GlobalSearchScope.allScope(getProject()))); |
| long count1 = tracker.getJavaStructureModificationCount(); |
| assertFalse(count1 == count0); |
| |
| document.deleteString(0, document.getTextLength()); |
| |
| // some plugins (e.g. Copyright) hold file reference in an invokeLater runnable, let them pass |
| UIUtil.dispatchAllInvocationEvents(); |
| |
| // gc softly-referenced file and AST |
| PlatformTestUtil.tryGcSoftlyReachableObjects(); |
| final PsiManagerEx psiManager = (PsiManagerEx)PsiManager.getInstance(getProject()); |
| assertNull(psiManager.getFileManager().getCachedPsiFile(file)); |
| |
| assertEquals(count1, tracker.getJavaStructureModificationCount()); // no PSI changes yet |
| //so the class should still be there |
| assertNotNull(JavaPsiFacade.getInstance(getProject()).findClass("Foo", GlobalSearchScope.allScope(getProject()))); |
| assertSize(1, ((PsiJavaFile)psiManager.findFile(file)).getClasses()); |
| assertEquals("class Foo {}", psiManager.findFile(file).getText()); |
| PlatformTestUtil.tryGcSoftlyReachableObjects(); |
| |
| PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); |
| |
| assertFalse(count1 == tracker.getJavaStructureModificationCount()); |
| assertNull(JavaPsiFacade.getInstance(getProject()).findClass("Foo", GlobalSearchScope.allScope(getProject()))); |
| } |
| }.execute(); |
| } |
| |
| } |