/* * Copyright 2000-2016 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.usages.impl; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.ExtensionsArea; import com.intellij.openapi.fileEditor.FileEditorLocation; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.testFramework.LightPlatformTestCase; import com.intellij.testFramework.VfsTestUtil; import com.intellij.usageView.UsageInfo; import com.intellij.usages.*; import com.intellij.usages.impl.rules.FileGroupingRule; import com.intellij.usages.rules.SingleParentUsageGroupingRule; import com.intellij.usages.rules.UsageGroupingRule; import com.intellij.usages.rules.UsageGroupingRuleProvider; import com.intellij.util.ArrayUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; import java.io.IOException; /** * @author max */ public class UsageNodeTreeBuilderTest extends LightPlatformTestCase { public void testNoGroupingRules() throws Exception { GroupNode groupNode = buildUsageTree(new int[]{2, 3, 0}, UsageGroupingRule.EMPTY_ARRAY); assertNotNull(groupNode); assertNull(groupNode.getParent()); assertEquals("Root [0, 2, 3]", groupNode.toString()); } public void testOneGroupingRuleOnly() throws Exception { GroupNode groupNode = buildUsageTree(new int[]{0, 1, 0, 1 , 1}, new UsageGroupingRule[] {new OddEvenGroupingRule()}); assertEquals("Root [Even[0, 0], Odd[1, 1, 1]]", groupNode.toString()); } public void testNotGroupedItemsComeToEnd() throws Exception { GroupNode groupNode = buildUsageTree(new int[]{0, 1, 0, 1 , 1, 1003, 1002, 1001}, new UsageGroupingRule[] {new OddEvenGroupingRule()}); assertEquals("Root [Even[0, 0], Odd[1, 1, 1], 1001, 1002, 1003]", groupNode.toString()); } public void test2Groupings() throws Exception { GroupNode groupNode = buildUsageTree(new int[]{0, 1, 2, 3, 12, 13, 14, 15, 101, 103, 102, 105, 10001, 10002, 10003}, new UsageGroupingRule[] { new OddEvenGroupingRule(), new LogGroupingRule()}); assertEquals("Root [Even[1[0, 2], 2[12, 14], 3[102]], Odd[1[1, 3], 2[13, 15], 3[101, 103, 105]], 5[10001, 10002, 10003]]", groupNode.toString()); } public void testDifferentRulesDontDependOnOrder() throws Exception { GroupNode groupNode = buildUsageTree(new int[]{10003, 0}, new UsageGroupingRule[] { new OddEvenGroupingRule(), new LogGroupingRule()}); assertEquals("Root [Even[1[0]], 5[10003]]", groupNode.toString()); } public void testGroupsFromDifferentRulesAreCorrectlySorted() throws Exception { GroupNode groupNode = buildUsageTree(new int[]{10003, 0, 1, 2, 3, 12, 13, 14, 15, 101, 103, 102, 105, 10001, 10002}, new UsageGroupingRule[] { new OddEvenGroupingRule(), new LogGroupingRule()}); assertEquals("Root [Even[1[0, 2], 2[12, 14], 3[102]], Odd[1[1, 3], 2[13, 15], 3[101, 103, 105]], 5[10001, 10002, 10003]]", groupNode.toString()); } private static Usage createUsage(int index) { return new MockUsage(index); } private GroupNode buildUsageTree(int[] indices, UsageGroupingRule[] rules) { Usage[] usages = new Usage[indices.length]; for (int i = 0; i < usages.length; i++) { usages[i] = createUsage(indices[i]); } UsageViewPresentation presentation = new UsageViewPresentation(); presentation.setUsagesString("searching for mock usages"); ExtensionsArea area = Extensions.getRootArea(); ExtensionPoint<UsageGroupingRuleProvider> point = area.getExtensionPoint(UsageGroupingRuleProvider.EP_NAME); UsageGroupingRuleProvider provider = new UsageGroupingRuleProvider() { @NotNull @Override public UsageGroupingRule[] getActiveRules(Project project) { return rules; } @NotNull @Override public AnAction[] createGroupingActions(UsageView view) { return AnAction.EMPTY_ARRAY; } }; point.registerExtension(provider); try { UsageViewImpl usageView = new UsageViewImpl(getProject(), presentation, UsageTarget.EMPTY_ARRAY, null); Disposer.register(getTestRootDisposable(), usageView); for (Usage usage : usages) { usageView.appendUsage(usage); } UIUtil.dispatchAllInvocationEvents(); return usageView.getRoot(); } finally { point.unregisterExtension(provider); } } private static class LogGroupingRule extends SingleParentUsageGroupingRule { @Nullable @Override protected UsageGroup getParentGroupFor(@NotNull Usage usage, @NotNull UsageTarget[] targets) { return new LogUsageGroup(usage.toString().length()); } } private static class LogUsageGroup implements UsageGroup { private final int myPower; LogUsageGroup(int power) { myPower = power; } @Override public void update() { } @Override public Icon getIcon(boolean isOpen) { return null; } @Override @NotNull public String getText(UsageView view) { return String.valueOf(myPower); } @Override public FileStatus getFileStatus() { return null; } @Override public boolean isValid() { return false; } public String toString() { return getText(null); } @Override public int compareTo(@NotNull UsageGroup o) { if (!(o instanceof LogUsageGroup)) return 1; return myPower - ((LogUsageGroup)o).myPower; } public boolean equals(Object o) { return o instanceof LogUsageGroup && myPower == ((LogUsageGroup)o).myPower; } public int hashCode() { return myPower; } @Override public void navigate(boolean requestFocus) { } @Override public boolean canNavigate() { return false; } @Override public boolean canNavigateToSource() { return false; } } private static class OddEvenGroupingRule extends SingleParentUsageGroupingRule { private static final UsageGroup EVEN = new UsageGroup() { @Override public Icon getIcon(boolean isOpen) { return null; } @Override @NotNull public String getText(UsageView view) { return "Even"; } @Override public void update() { } @Override public FileStatus getFileStatus() { return null; } @Override public boolean isValid() { return false; } @Override public void navigate(boolean focus) throws UnsupportedOperationException { } @Override public boolean canNavigate() { return false; } @Override public boolean canNavigateToSource() { return false; } @Override public int compareTo(@NotNull UsageGroup o) { return o == ODD ? -1 : 0; } public String toString() { return getText(null); } }; private static final UsageGroup ODD = new UsageGroup() { @Override public Icon getIcon(boolean isOpen) { return null; } @Override @NotNull public String getText(UsageView view) { return "Odd"; } @Override public void update() { } @Override public FileStatus getFileStatus() { return null; } @Override public boolean isValid() { return false; } @Override public void navigate(boolean focus) throws UnsupportedOperationException { } @Override public boolean canNavigate() { return false; } @Override public boolean canNavigateToSource() { return false; } @Override public int compareTo(@NotNull UsageGroup o) { return o == EVEN ? 1 : 0; } @Override public String toString() { return getText(null); } }; @Nullable @Override protected UsageGroup getParentGroupFor(@NotNull Usage usage, @NotNull UsageTarget[] targets) { MockUsage mockUsage = (MockUsage)usage; if (mockUsage.getId() > 1000) return null; return mockUsage.getId() % 2 == 0 ? EVEN : ODD; } } private static class MockUsage implements Usage { private final int myId; MockUsage(int index) { myId = index; } public int getId() { return myId; } @Override @NotNull public UsagePresentation getPresentation() { return new UsagePresentation() { @Override @NotNull public TextChunk[] getText() { return TextChunk.EMPTY_ARRAY; } @Override @NotNull public String getPlainText() { return ""; } @Override public Icon getIcon() { return null; } @Override public String getTooltipText() { return null; } }; } @Override public boolean isValid() { return true; } @Override public FileEditorLocation getLocation() { return null; } @Override public void selectInEditor() { } @Override public void highlightInEditor() { } public String toString() { return String.valueOf(myId); } @Override public void navigate(boolean requestFocus) { } @Override public boolean canNavigate() { return false; } @Override public boolean canNavigateToSource() { return false; } @Override public boolean isReadOnly() { return false; } } public void testFilesWithTheSameNameButDifferentPathsEndUpInDifferentGroups() throws IOException { File ioDir = FileUtil.createTempDirectory("t", null, false); VirtualFile dir = null; try { dir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioDir); PsiFile f1 = getPsiManager().findFile(VfsTestUtil.createFile(dir, "/x/X.java", "class X{}")); PsiFile f2 = getPsiManager().findFile(VfsTestUtil.createFile(dir, "/y/X.java", "class X{}")); PsiElement class1 = ArrayUtil.getLastElement(f1.getChildren()); PsiElement class2 = ArrayUtil.getLastElement(f2.getChildren()); FileGroupingRule fileGroupingRule = new FileGroupingRule(getProject()); UsageGroup group1 = fileGroupingRule.getParentGroupFor(new UsageInfo2UsageAdapter(new UsageInfo(class1)), UsageTarget.EMPTY_ARRAY); UsageGroup group2 = fileGroupingRule.getParentGroupFor(new UsageInfo2UsageAdapter(new UsageInfo(class2)), UsageTarget.EMPTY_ARRAY); int compareTo = group1.compareTo(group2); assertTrue(String.valueOf(compareTo), compareTo < 0); } finally { if (dir != null) { VfsTestUtil.deleteFile(dir); } FileUtil.delete(ioDir); } } }