diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/VfsIndexer.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/VfsIndexer.java deleted file mode 100644 index a0bf1e3a792b..000000000000 --- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/VfsIndexer.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2000-2009 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.impl.cache.impl; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileFilter; -import com.intellij.psi.PsiBundle; - -import java.io.*; -import java.util.ArrayList; -import java.util.List; - -public class VfsIndexer { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.cache.impl.VfsIndexer"); - - public static VirtualFile[] writeFileIndex( - OutputStream stream, - VirtualFile root, - VirtualFileFilter filter) throws IOException { - - List result = new ArrayList(); - - ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator(); - if (progress != null){ - progress.setText2(PsiBundle.message("psi.scanning.files.in.folder.progress", root.getPresentableUrl())); - } - - DataOutputStream out = stream == null ? null : new DataOutputStream(stream); - - _writeFileIndex(out, root, filter, result); - - if (out != null){ - out.flush(); - } - - return VfsUtil.toVirtualFileArray(result); - } - - private static void _writeFileIndex(DataOutputStream out, VirtualFile file, VirtualFileFilter filter, List result) throws IOException { - ProgressManager.checkCanceled(); - - result.add(file); - if (out != null){ - out.writeUTF(file.getName()); - } - - VirtualFile[] children = file.getChildren(); - if (children == null) { - if (out != null){ - out.writeInt(0); - } - return; - } - - int childrenCount = 0; - for (VirtualFile child : children) { - if (filter.accept(child)) childrenCount++; - } - - if (out != null){ - out.writeInt(childrenCount); - } - for (VirtualFile child : children) { - if (filter.accept(child)) { - _writeFileIndex(out, child, filter, result); - } - } - } - - public static VirtualFile[] readFileIndex( - InputStream stream, - VirtualFile root, - VirtualFileFilter filter - ) throws IOException { - List result = new ArrayList(); - - DataInputStream in = new DataInputStream(stream); - - String rootName = in.readUTF(); - LOG.assertTrue(root.getName().equals(rootName)); - _readFileIndex(in, root, filter, result); - - return VfsUtil.toVirtualFileArray(result); - } - - private static void _readFileIndex(DataInputStream in, VirtualFile file, VirtualFileFilter filter, List result) throws IOException { - ProgressManager.checkCanceled(); - - result.add(file); - int childrenCount = in.readInt(); - if (childrenCount == 0) return; - - for (int i = 0; i < childrenCount; i++) { - String name = in.readUTF(); - VirtualFile child = file != null ? file.findChild(name) : null; - - if (child != null && !filter.accept(child)){ - child = null; - } - - _readFileIndex(in, child, filter, result); - } - } -} diff --git a/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java b/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java new file mode 100644 index 000000000000..84e06a1f9d02 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/run/PathMacrosCollectorTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package com.intellij.run; + +import com.intellij.application.options.PathMacrosCollector; +import com.intellij.application.options.PathMacrosImpl; +import com.intellij.util.NotNullFunction; +import junit.framework.TestCase; +import org.jdom.Attribute; +import org.jdom.Element; +import org.jdom.Text; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +/** + * @author Eugene Zhuravlev + * Date: Nov 14, 2006 + */ +public class PathMacrosCollectorTest extends TestCase { + public void testCollectMacros() { + Element root = new Element("root"); + root.addContent(new Text("$MACro1$ some text $macro2$ other text $MACRo3$")); + root.addContent(new Text("$macro4$ some text")); + root.addContent(new Text("some text$macro5$")); + root.addContent(new Text("file:$mac_ro6$")); + root.addContent(new Text("jar://$macr.o7$ ")); + root.addContent(new Text("$mac-ro8$ ")); + root.addContent(new Text("$$$ ")); + root.addContent(new Text("$c:\\a\\b\\c$ ")); + root.addContent(new Text("$Revision 1.23$")); + + final Set macros = PathMacrosCollector.getMacroNames(root, null, null, new PathMacrosImpl()); + + assertEquals(5, macros.size()); + assertTrue(macros.contains("MACro1")); + assertTrue(macros.contains("macro4")); + assertTrue(macros.contains("mac_ro6")); + assertTrue(macros.contains("macr.o7")); + assertTrue(macros.contains("mac-ro8")); + } + + public void testWithRecursiveFilter() throws Exception { + Element root = new Element("root"); + final Element configuration = new Element("configuration"); + configuration.setAttribute("value", "some text$macro5$fdsjfhdskjfsd$MACRO$"); + root.addContent(configuration); + + final Set macros = PathMacrosCollector.getMacroNames(root, null, new NotNullFunction() { + @Override + @NotNull + public Boolean fun(Object o) { + return (o instanceof Attribute) && "value".equals(((Attribute)o).getName()); + } + }, new PathMacrosImpl()); + + assertEquals(2, macros.size()); + assertTrue(macros.contains("macro5")); + assertTrue(macros.contains("MACRO")); + } + + public void testWithFilter() throws Exception { + Element root = new Element("root"); + final Element testTag = new Element("test"); + testTag.setAttribute("path", "$MACRO$"); + testTag.setAttribute("ignore", "$PATH$"); + root.addContent(testTag); + + final Set macros = PathMacrosCollector.getMacroNames(root, null, null, new PathMacrosImpl()); + assertEquals(2, macros.size()); + assertTrue(macros.contains("MACRO")); + assertTrue(macros.contains("PATH")); + + final Set filtered = PathMacrosCollector.getMacroNames(root, new NotNullFunction() { + @Override + @NotNull + public Boolean fun(Object o) { + if (o instanceof Attribute && "ignore".equals(((Attribute)o).getName())) return false; + return true; + } + }, null, new PathMacrosImpl()); + + assertEquals(1, filtered.size()); + assertTrue(macros.contains("MACRO")); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/structureView/TestGrouper.java b/platform/platform-tests/testSrc/com/intellij/structureView/TestGrouper.java new file mode 100644 index 000000000000..f4474c547514 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/structureView/TestGrouper.java @@ -0,0 +1,102 @@ +package com.intellij.structureView; + +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.ide.util.treeView.smartTree.ActionPresentation; +import com.intellij.ide.util.treeView.smartTree.Group; +import com.intellij.ide.util.treeView.smartTree.Grouper; +import com.intellij.ide.util.treeView.smartTree.TreeElement; +import com.intellij.navigation.ItemPresentation; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class TestGrouper implements Grouper { + private final String[] mySubStrings; + + public TestGrouper(String[] subString) { + mySubStrings = subString; + } + + @Override + @NotNull + public ActionPresentation getPresentation() { + throw new RuntimeException(); + } + + @Override + @NotNull + public String getName() { + throw new RuntimeException(); + } + + private class StringGroup implements Group { + private final String myString; + private final Collection myChildren; + private final Collection myChildrenUsedStrings; + + public StringGroup(String string, final Collection children, Collection childrenStrings) { + myString = string; + myChildrenUsedStrings = childrenStrings; + myChildren = new ArrayList(children); + } + + @Override + public Collection getChildren() { + Collection result = new LinkedHashSet(); + for (TreeElement object : myChildren) { + if (object.toString().indexOf(myString) >= 0) { + result.add(object); + } + } + return result; + } + + @Override + public ItemPresentation getPresentation() { + return null; + } + + public String toString() { + return "Group:" + myString; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Group)) return false; + + final StringGroup group = (StringGroup)o; + + if (myString != null ? !myString.equals(group.myString) : group.myString != null) return false; + + return true; + } + + public int hashCode() { + return (myString != null ? myString.hashCode() : 0); + } + } + + @Override + @NotNull + public Collection group(final AbstractTreeNode parent, Collection children) { + List result = new ArrayList(); + Collection parentGroupUsedStrings = parent.getValue() instanceof StringGroup ? + ((StringGroup)parent.getValue()).myChildrenUsedStrings : + Collections.emptySet(); + Collection elements = new LinkedHashSet(children); + for (String subString : mySubStrings) { + if (parentGroupUsedStrings.contains(subString)) continue; + Set childrenStrings = new THashSet(parentGroupUsedStrings); + ContainerUtil.addAll(childrenStrings, mySubStrings); + StringGroup group = new StringGroup(subString, elements, childrenStrings); + Collection groupChildren = group.getChildren(); + if (!groupChildren.isEmpty()) { + elements.removeAll(groupChildren); + result.add(group); + } + } + return result; + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/structureView/TestTreeModel.java b/platform/platform-tests/testSrc/com/intellij/structureView/TestTreeModel.java new file mode 100644 index 000000000000..28dacd889fa8 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/structureView/TestTreeModel.java @@ -0,0 +1,142 @@ +package com.intellij.structureView; + +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.structureView.FileEditorPositionListener; +import com.intellij.ide.structureView.ModelListener; +import com.intellij.ide.structureView.StructureViewModel; +import com.intellij.ide.structureView.StructureViewTreeElement; +import com.intellij.ide.util.treeView.smartTree.Filter; +import com.intellij.ide.util.treeView.smartTree.Grouper; +import com.intellij.ide.util.treeView.smartTree.Sorter; +import com.intellij.navigation.ItemPresentation; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class TestTreeModel implements StructureViewModel{ + private final StringTreeElement myRoot; + private final List myFilters = new ArrayList(); + private final List mySorters = new ArrayList(); + + public TestTreeModel(StringTreeElement root) { + myRoot = root; + + } + + @Override + @NotNull + public StructureViewTreeElement getRoot() { + return myRoot; + } + + @Override + @NotNull + public Filter[] getFilters() { + return myFilters.toArray(new Filter[myFilters.size()]); + } + + @Override + @NotNull + public Grouper[] getGroupers() { + return new Grouper[]{new TestGrouper(new String[]{"a", "b", "c"}), + new TestGrouper(new String[]{"d", "e", "f"})}; + } + + @Override + @NotNull + public Sorter[] getSorters() { + return mySorters.toArray(new Sorter[mySorters.size()]); + } + + public void addFlter(Filter filter) { + myFilters.add(filter); + } + + public void addSorter(Sorter sorter) { + mySorters.add(sorter); + } + + public static class StringTreeElement implements StructureViewTreeElement { + private final Collection myChildren = new ArrayList(); + private final String myValue; + + public StringTreeElement(@NonNls String value) { + myValue = value; + } + + @Override + public StructureViewTreeElement[] getChildren() { + return myChildren.toArray(new StructureViewTreeElement[myChildren.size()]); + + } + + @Override + public ItemPresentation getPresentation() { + return new PresentationData(myValue, null, null, null, null); + } + + public String toString() { + return myValue; + } + + public StringTreeElement addChild(@NonNls String s) { + StringTreeElement child = new StringTreeElement(s); + myChildren.add(child); + return child; + } + + @Override + public String getValue() { + return myValue; + } + + @Override + public void navigate(boolean requestFocus) { + } + + @Override + public boolean canNavigate() { + return false; + } + + @Override + public boolean canNavigateToSource() { + return false; + } + } + + @Override + public Object getCurrentEditorElement() { + return null; + } + + @Override + public void addEditorPositionListener(FileEditorPositionListener listener) { + } + + @Override + public void removeEditorPositionListener(FileEditorPositionListener listener) { + } + + @Override + public void dispose() { + } + + @Override + public boolean shouldEnterElement(final Object element) { + return false; + } + + @Override + public void addModelListener(ModelListener modelListener) { + + } + + @Override + public void removeModelListener(ModelListener modelListener) { + + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/usagesStatistics/RemotelyConfigurableStatServiceTest.java b/platform/platform-tests/testSrc/com/intellij/usagesStatistics/RemotelyConfigurableStatServiceTest.java new file mode 100644 index 000000000000..7dd8e8d2c063 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/usagesStatistics/RemotelyConfigurableStatServiceTest.java @@ -0,0 +1,79 @@ +package com.intellij.usagesStatistics; + +import com.intellij.internal.statistic.StatisticsUploadAssistant; +import com.intellij.internal.statistic.connect.StatisticsHttpClientSender; +import com.intellij.internal.statistic.connect.RemotelyConfigurableStatisticsService; +import com.intellij.internal.statistic.connect.StatisticsConnectionService; +import com.intellij.internal.statistic.connect.StatisticsResult; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.jetbrains.annotations.NonNls; + +public class RemotelyConfigurableStatServiceTest extends TestCase { + + @NonNls + private static final String STAT_URL = "http://localhost:8080/stat.jsp"; + + @NonNls + private static final String STAT_CONFIG_URL = "http://localhost:8080/config.jsp"; + + public void testStatisticsConnectionServiceDefaultSettings() { + final StatisticsConnectionService connectionService = new StatisticsConnectionService(STAT_CONFIG_URL, STAT_URL); + + Assert.assertEquals(STAT_URL, connectionService.getServiceUrl()); + Assert.assertTrue(connectionService.isTransmissionPermitted()); + final String[] attributeNames = connectionService.getAttributeNames(); + + Assert.assertEquals(attributeNames.length, 2); + Assert.assertEquals(attributeNames[0], "url"); + Assert.assertEquals(attributeNames[1], "permitted"); + } + + public void testEmptyDataSending() { + RemotelyConfigurableStatisticsService service = new RemotelyConfigurableStatisticsService(new StatisticsConnectionService(), + new StatisticsHttpClientSender(), + new StatisticsUploadAssistant() { + @Override + public String getData() { + return ""; + } + }); + final StatisticsResult result = service.send(); + Assert.assertEquals(StatisticsResult.ResultCode.NOTHING_TO_SEND, result.getCode()); + } + + public void testIncorrectUrlSending() { + RemotelyConfigurableStatisticsService service = new RemotelyConfigurableStatisticsService(new StatisticsConnectionService(STAT_CONFIG_URL, STAT_URL), + new StatisticsHttpClientSender(), + new StatisticsUploadAssistant() { + @Override + public String getData() { + return "group:key1=11"; + } + }); + final StatisticsResult result = service.send(); + Assert.assertEquals(StatisticsResult.ResultCode.SEND_WITH_ERRORS, result.getCode()); + } + + public void testRemotelyDisabledTransmission() { + RemotelyConfigurableStatisticsService service = new RemotelyConfigurableStatisticsService(new StatisticsConnectionService() { + @Override + public Boolean isTransmissionPermitted() { + return false; + } + }, new StatisticsHttpClientSender(), + new StatisticsUploadAssistant()); + + final StatisticsResult result = service.send(); + Assert.assertEquals(StatisticsResult.ResultCode.NOT_PERMITTED_SERVER, result.getCode()); + } + + public void testErrorInRemoteConfiguration() { + RemotelyConfigurableStatisticsService service = + new RemotelyConfigurableStatisticsService(new StatisticsConnectionService(STAT_CONFIG_URL, null), + new StatisticsHttpClientSender(), + new StatisticsUploadAssistant()); + final StatisticsResult result = service.send(); + Assert.assertEquals(StatisticsResult.ResultCode.ERROR_IN_CONFIG, result.getCode()); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/usagesStatistics/StatisticsUploadAssistantTest.java b/platform/platform-tests/testSrc/com/intellij/usagesStatistics/StatisticsUploadAssistantTest.java new file mode 100644 index 000000000000..899f2a0e37d0 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/usagesStatistics/StatisticsUploadAssistantTest.java @@ -0,0 +1,245 @@ +package com.intellij.usagesStatistics; + +import com.intellij.internal.statistic.StatisticsUploadAssistant; +import com.intellij.internal.statistic.beans.ConvertUsagesUtil; +import com.intellij.internal.statistic.beans.GroupDescriptor; +import com.intellij.internal.statistic.beans.PatchedUsage; +import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.internal.statistic.persistence.BasicSentUsagesPersistenceComponent; +import com.intellij.internal.statistic.persistence.SentUsagesPersistence; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.hash.HashMap; +import com.intellij.util.containers.hash.LinkedHashMap; +import junit.framework.TestCase; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class StatisticsUploadAssistantTest extends TestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testCreateNewPatch() { + final Map> all = createDescriptors("g:a1:1", "g:a2:2", "g:a3:3"); + final Map> sent = new HashMap>(); + + final Map> patched = StatisticsUploadAssistant.getPatchedUsages(all, sent); + + assertMapEquals(patched, createDescriptors("g:a1:1", "g:a2:2", "g:a3:3")); + } + + public void testEmptyPatchs() { + final Map> all = new HashMap>(); + final Map> sent = new HashMap>(); + assertEquals(StatisticsUploadAssistant.getPatchedUsages(all, sent).size(), 0); + } + + public void testCreateEmptyPatch() { + final Map> all = createDescriptors("g:a1:1", "g:a2:2", "g:a3:3", "g2:a1:1", "g2:a2:2", "g2:a3:3"); + final Map> sent = createDescriptors("g:a1:1", "g:a2:2", "g:a3:3", "g2:a1:1", "g2:a2:2", "g2:a3:3"); + + assertEquals(StatisticsUploadAssistant.getPatchedUsages(all, sent).size(), 0); + } + + public void testCreatePatchEmptyAll() { + final Map> all = new HashMap>(); + final Map> sent = createDescriptors("g:a1:1", "g:a2:2", "g2:a1:1", "g2:a2:2", "g2:a3:3"); + + final Map> patched = StatisticsUploadAssistant.getPatchedUsages(all, sent); + + assertMapEquals(patched, createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g2:a1:-1")); + } + + public void testCreatePatchMerged() { + final Map> all = createDescriptors("g:a1:100", "g:a2:2", "g2:a1:0", "g2:a2:1"); + final Map> sent = createDescriptors("g:a1:2", "g:a2:100", "g2:a1:1", "g2:a2:1", "g2:a3:3"); + + final Map> patched = StatisticsUploadAssistant.getPatchedUsages(all, sent); + + assertMapEquals(patched, createDescriptors("g:a1:98", "g:a2:-98", "g2:a1:-1", "g2:a3:-3")); + } + + public void testPersistSentPatch() { + final Map> allUsages = createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g2:a1:-1", "g3:a1:13"); + final SentUsagesPersistence usagesPersistence = new BasicSentUsagesPersistenceComponent(); + + Map> patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence); + String result = StatisticsUploadAssistant.getStringPatch(patchedUsages, 500); + StatisticsUploadAssistant.persistSentPatch(result, usagesPersistence); + + assertMapEquals(ConvertUsagesUtil.convertString(result), ConvertUsagesUtil.convertString("g:a2=-2,a1=-1;g2:a3=-3,a2=-2,a1=-1;g3:a1=13;")); + + patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence); + result = StatisticsUploadAssistant.getStringPatch(patchedUsages, 500); + StatisticsUploadAssistant.persistSentPatch(result, usagesPersistence); + + assertEquals("sent usages must be persisted", result.length(), 0); + assertEquals(allUsages.size(), usagesPersistence.getSentUsages().size()); + } + + public void testConvertUsages() { + final Map> patchedUsages = StatisticsUploadAssistant + .getPatchedUsages(createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g2:a1:-1", "g3:a1:13"), + new HashMap>()); + + final String result = ConvertUsagesUtil.convertUsages(patchedUsages); + final Map> convertedUsages = ConvertUsagesUtil.convertString(result); + + assertMapEquals(patchedUsages, convertedUsages); + } + + public void testConvertUsagesWithPriority() { + final Map> patchedUsages = new HashMap>(); + + createPatchDescriptor(patchedUsages, "low", GroupDescriptor.LOWER_PRIORITY, "l1", 1); + createPatchDescriptor(patchedUsages, "low", GroupDescriptor.LOWER_PRIORITY, "l2", 1); + createPatchDescriptor(patchedUsages, "high", GroupDescriptor.HIGHER_PRIORITY, "h", 1); + createPatchDescriptor(patchedUsages, "high", GroupDescriptor.HIGHER_PRIORITY, "h2", 1); + createPatchDescriptor(patchedUsages, "default_1", GroupDescriptor.DEFAULT_PRIORITY, "d11", 1); + createPatchDescriptor(patchedUsages, "default_2", GroupDescriptor.DEFAULT_PRIORITY, "d21", 1); + createPatchDescriptor(patchedUsages, "default_1", GroupDescriptor.DEFAULT_PRIORITY, "d12", 1); + + + assertEquals(ConvertUsagesUtil.convertUsages(patchedUsages), + "high:h=1,h2=1;default_1:d11=1,d12=1;default_2:d21=1;low:l1=1,l2=1;"); + } + + public void testConvertUsagesWithEqualPriority() { + final Map> patchedUsages = new HashMap>(); + + createPatchDescriptor(patchedUsages, "g4", GroupDescriptor.HIGHER_PRIORITY, "1", 1); + createPatchDescriptor(patchedUsages, "g2", GroupDescriptor.HIGHER_PRIORITY, "2", 1); + createPatchDescriptor(patchedUsages, "g1", GroupDescriptor.HIGHER_PRIORITY, "3", 1); + createPatchDescriptor(patchedUsages, "g3", GroupDescriptor.HIGHER_PRIORITY, "4", 1); + + + assertEquals(ConvertUsagesUtil.convertUsages(patchedUsages), "g1:3=1;g2:2=1;g3:4=1;g4:1=1;"); + } + + public void testConvertString() { + final Map> patchedUsages = new HashMap>(); + + createPatchDescriptor(patchedUsages, "g4", GroupDescriptor.HIGHER_PRIORITY, "1", 1); + createPatchDescriptor(patchedUsages, "g2", GroupDescriptor.HIGHER_PRIORITY, "2", 1); + createPatchDescriptor(patchedUsages, "g1", GroupDescriptor.HIGHER_PRIORITY, "3", 1); + createPatchDescriptor(patchedUsages, "g3", GroupDescriptor.HIGHER_PRIORITY, "4", 1); + + assertMapEquals(patchedUsages, ConvertUsagesUtil.convertString("g3:4=1;g1:3=1;g4:1=1;g2:2=1;")); + } + + public void testConvertEmptyString() { + assertEquals(ConvertUsagesUtil.convertString("").size(), 0); + } + + public void testConvertBrokenString() { + assertEquals(ConvertUsagesUtil.convertString("asdfasdfsad").size(), 0); + assertEquals(ConvertUsagesUtil.convertString("asdf:asdfsad").size(), 0); + assertEquals(ConvertUsagesUtil.convertString("asdfa:sd;fsad").size(), 0); + assertEquals(ConvertUsagesUtil.convertString("asdfa:sd;fs,ad").size(), 0); + assertEquals(ConvertUsagesUtil.convertString("asdfa:sd;f;sad").size(), 0); + assertEquals(ConvertUsagesUtil.convertString("asdfa:sd=ds2,f=f,sad=;").size(), 0); + } + + public void testPersistSentPatchWithRestrictedSize() { + int size = 15; + final Map> allUsages = createDescriptors("g:a1:-1", "g2:a2:-2", "g2:a3:-3", "g:a2:-2", "g3:a1:-1", "g3:a2:13"); + + final SentUsagesPersistence usagesPersistence = new BasicSentUsagesPersistenceComponent(); + Map> patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence); + String first = StatisticsUploadAssistant.getStringPatch(patchedUsages, size); + StatisticsUploadAssistant.persistSentPatch(first, usagesPersistence); + + assertTrue(first.length() <= size); + assertMapEquals(ConvertUsagesUtil.convertString(first), ConvertUsagesUtil.convertString("g:a1=-1,a2=-2")); + + patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence); + String second = StatisticsUploadAssistant.getStringPatch(patchedUsages, size); + StatisticsUploadAssistant.persistSentPatch(second, usagesPersistence); + assertTrue(second.length() <= size); + assertFalse(second.contains(first)); + assertMapEquals(ConvertUsagesUtil.convertString(second), ConvertUsagesUtil.convertString("g2:a2=-2,a3=-3")); + + patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence); + String third = StatisticsUploadAssistant.getStringPatch(patchedUsages, size); + StatisticsUploadAssistant.persistSentPatch(third, usagesPersistence); + assertTrue(third.length() <= size); + assertFalse(third.contains(first)); + assertFalse(third.contains(second)); + assertMapEquals(ConvertUsagesUtil.convertString(third), ConvertUsagesUtil.convertString("g3:a1=-1,a2=13")); + + + patchedUsages = StatisticsUploadAssistant.getPatchedUsages(allUsages, usagesPersistence); + assertEquals(patchedUsages.size(), 0); + + assertEquals(allUsages.size(), usagesPersistence.getSentUsages().size()); + } + + private static void assertMapEquals(@NotNull Map> expected, @NotNull Map> actual) { + assertEquals(expected.size(), actual.size()); + + for (Map.Entry> expectedEntry : expected.entrySet()) { + final GroupDescriptor expectedGroupDescriptor = expectedEntry.getKey(); + + assertTrue(actual.containsKey(expectedGroupDescriptor)); + + assertSetEquals(expectedEntry.getValue(), actual.get(expectedEntry.getKey())); + } + } + + private static void assertSetEquals(@NotNull Set expected, @NotNull Set actual) { + assertEquals(expected.size(), actual.size()); + for (UsageDescriptor usageDescriptor : expected) { + boolean exists = false; + for (UsageDescriptor descriptor : actual) { + if (usageDescriptor.getKey().equals(descriptor.getKey()) && usageDescriptor.getValue() == descriptor.getValue()) { + exists = true; + break; + } + } + assertTrue(asString(usageDescriptor) + " usage doesn't exist", exists); + } + } + + private static String asString(UsageDescriptor usage) { + return usage.getKey() + "=" + usage.getValue(); + } + + private static void createPatchDescriptor(Map> patchedUsages, String groupId, double priority, String key, int i) { + final GroupDescriptor groupDescriptor = GroupDescriptor.create(groupId, priority); + + if (!patchedUsages.containsKey(groupDescriptor)){ + patchedUsages.put(groupDescriptor, new LinkedHashSet()); + } + patchedUsages.get(groupDescriptor).add(new PatchedUsage(key, i)); + } + + + protected static UsageDescriptor createDescriptor(String k, int i) { + return new UsageDescriptor(k, i); + } + + protected static Map> createDescriptors(String... strs) { + Map> set = new LinkedHashMap>(); + for (String str : strs) { + final List list = StringUtil.split(str, ":"); + final GroupDescriptor g = GroupDescriptor.create(list.get(0)); + if (!set.containsKey(g)) { + set.put(g, new LinkedHashSet()); + } + set.get(g).add(createDescriptor(list.get(1), Integer.parseInt(list.get(2)))); + } + + return set; + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/util/io/BTreeEnumeratorTest.java b/platform/platform-tests/testSrc/com/intellij/util/io/BTreeEnumeratorTest.java new file mode 100644 index 000000000000..c666f358d4d2 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/util/io/BTreeEnumeratorTest.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2006 JetBrains s.r.o. All Rights Reserved. + */ +package com.intellij.util.io; + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.util.ThrowableRunnable; +import com.intellij.util.containers.IntObjectCache; +import gnu.trove.THashMap; +import junit.framework.TestCase; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class BTreeEnumeratorTest extends TestCase { + private static final String COLLISION_1 = ""; + private static final String COLLISION_2 = "\u0000"; + private static final String UTF_1 = "\ue534"; + private static final String UTF_2 = + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + + static class TestStringEnumerator extends PersistentBTreeEnumerator { + public TestStringEnumerator(File file) throws IOException { + super(file, new EnumeratorStringDescriptor(), 4096); + } + } + private TestStringEnumerator myEnumerator; + private File myFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + myFile = FileUtil.createTempFile("persistent", "trie"); + myEnumerator = new TestStringEnumerator(myFile); + } + + @Override + protected void tearDown() throws Exception { + myEnumerator.close(); + FileUtil.delete(myFile); + FileUtil.delete(new File(myFile.getParentFile(), myFile.getName() + ".len")); + assertTrue(!myFile.exists()); + super.tearDown(); + } + + public void testAddEqualStrings() throws IOException { + final int index = myEnumerator.enumerate("IntelliJ IDEA"); + myEnumerator.enumerate("Just another string"); + assertEquals(index, myEnumerator.enumerate("IntelliJ IDEA")); + } + + public void testAddEqualStringsAndMuchGarbage() throws IOException { + final Map strings = new THashMap(10001); + String s = "IntelliJ IDEA"; + final int index = myEnumerator.enumerate(s); + strings.put(index, s); + + // clear strings and nodes cache + for (int i = 0; i < 10000; ++i) { + final String v = Integer.toString(i) + "Just another string"; + final int idx = myEnumerator.enumerate(v); + assertEquals(v, myEnumerator.valueOf(idx)); + strings.put(idx, v); + } + + for(Map.Entry e:strings.entrySet()) { + assertEquals((int)e.getKey(), myEnumerator.enumerate(e.getValue())); + } + + final Set enumerated = new HashSet(myEnumerator.getAllDataObjects(null)); + assertEquals(new HashSet(strings.values()), enumerated); + } + + public void testCollision() throws Exception { + int id1 = myEnumerator.enumerate(COLLISION_1); + int id2 = myEnumerator.enumerate(COLLISION_2); + assertFalse(id1 == id2); + + assertEquals(COLLISION_1, myEnumerator.valueOf(id1)); + assertEquals(COLLISION_2, myEnumerator.valueOf(id2)); + assertEquals(new HashSet(Arrays.asList(COLLISION_1, COLLISION_2)), new HashSet(myEnumerator.getAllDataObjects(null))); + } + + public void testCollision1() throws Exception { + int id1 = myEnumerator.enumerate(COLLISION_1); + + assertEquals(id1, myEnumerator.tryEnumerate(COLLISION_1)); + assertEquals(PersistentEnumerator.NULL_ID, myEnumerator.tryEnumerate(COLLISION_2)); + + int id2 = myEnumerator.enumerate(COLLISION_2); + assertFalse(id1 == id2); + + assertEquals(id1, myEnumerator.tryEnumerate(COLLISION_1)); + assertEquals(id2, myEnumerator.tryEnumerate(COLLISION_2)); + assertEquals(PersistentEnumerator.NULL_ID, myEnumerator.tryEnumerate("some string")); + + assertEquals(COLLISION_1, myEnumerator.valueOf(id1)); + assertEquals(COLLISION_2, myEnumerator.valueOf(id2)); + assertEquals(new HashSet(Arrays.asList(COLLISION_1, COLLISION_2)), new HashSet(myEnumerator.getAllDataObjects(null))); + } + + + public void testUTFString() throws Exception { + int id1 = myEnumerator.enumerate(UTF_1); + int id2 = myEnumerator.enumerate(UTF_2); + assertFalse(id1 == id2); + + assertEquals(UTF_1, myEnumerator.valueOf(id1)); + assertEquals(UTF_2, myEnumerator.valueOf(id2)); + assertEquals(new HashSet(Arrays.asList(UTF_1, UTF_2)), new HashSet(myEnumerator.getAllDataObjects(null))); + } + + public void testOpeningClosing() throws IOException { + ArrayList strings = new ArrayList(2000); + for (int i = 0; i < 2000; ++i) { + strings.add(createRandomString()); + } + for (int i = 0; i < 2000; ++i) { + myEnumerator.enumerate(strings.get(i)); + myEnumerator.close(); + myEnumerator = new TestStringEnumerator(myFile); + } + for (int i = 0; i < 2000; ++i) { + myEnumerator.enumerate(strings.get(i)); + assertTrue(!myEnumerator.isDirty()); + myEnumerator.close(); + myEnumerator = new TestStringEnumerator(myFile); + } + for (int i = 0; i < 2000; ++i) { + assertTrue(!myEnumerator.isDirty()); + myEnumerator.close(); + myEnumerator = new TestStringEnumerator(myFile); + } + final HashSet allStringsSet = new HashSet(strings); + assertEquals(allStringsSet, new HashSet(myEnumerator.getAllDataObjects(null))); + + final String additionalString = createRandomString(); + allStringsSet.add(additionalString); + myEnumerator.enumerate(additionalString); + assertTrue(myEnumerator.isDirty()); + assertEquals(allStringsSet, new HashSet(myEnumerator.getAllDataObjects(null))); + } + + public void testPerformance() throws IOException { + final IntObjectCache stringCache = new IntObjectCache(2000); + final IntObjectCache.DeletedPairsListener listener = new IntObjectCache.DeletedPairsListener() { + @Override + public void objectRemoved(final int key, final Object value) { + try { + assertEquals(myEnumerator.enumerate((String)value), key); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + + PlatformTestUtil.startPerformanceTest("PersistentStringEnumerator performance failed", 2500, new ThrowableRunnable() { + @Override + public void run() throws Exception { + stringCache.addDeletedPairsListener(listener); + for (int i = 0; i < 100000; ++i) { + final String string = createRandomString(); + stringCache.cacheObject(myEnumerator.enumerate(string), string); + } + stringCache.removeDeletedPairsListener(listener); + stringCache.removeAll(); + } + }).assertTiming(); + myEnumerator.close(); + System.out.printf("File size = %d bytes\n", myFile.length()); + } + + private static final StringBuilder builder = new StringBuilder(100); + private static final Random random = new Random(13101977); + + static String createRandomString() { + builder.setLength(0); + int len = random.nextInt(40) + 10; + for (int i = 0; i < len; ++i) { + builder.append((char)(32 + random.nextInt(2 + i >> 1))); + } + return builder.toString(); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/util/io/PersistentMapTest.java b/platform/platform-tests/testSrc/com/intellij/util/io/PersistentMapTest.java new file mode 100644 index 000000000000..26406e674577 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/util/io/PersistentMapTest.java @@ -0,0 +1,342 @@ +package com.intellij.util.io; + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.util.ThrowableRunnable; +import com.intellij.util.containers.IntObjectCache; +import com.intellij.util.io.storage.Storage; +import junit.framework.TestCase; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.*; + +/** + * @author Eugene Zhuravlev + * Date: Dec 19, 2007 + */ +public class PersistentMapTest extends TestCase { + + private PersistentHashMap myMap; + private File myFile; + private File myDataFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + myFile = FileUtil.createTempFile("persistent", "map"); + myDataFile = new File(myFile.getParentFile(), myFile.getName() + PersistentHashMap.DATA_FILE_EXTENSION); + myMap = new PersistentHashMap(myFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); + } + + @Override + protected void tearDown() throws Exception { + clearMap(myFile, myMap); + super.tearDown(); + } + + private static void clearMap(final File file1, PersistentHashMap map) throws IOException { + map.close(); + + final File[] files = file1.getParentFile().listFiles(new FileFilter() { + @Override + public boolean accept(final File pathname) { + return pathname.getName().startsWith(file1.getName()); + } + }); + + if (files != null) { + for (File file : files) { + FileUtil.delete(file); + assertTrue(!file.exists()); + } + } + } + + public void testMap() throws IOException { + myMap.put("AAA", "AAA_VALUE"); + + assertEquals("AAA_VALUE", myMap.get("AAA")); + assertNull(myMap.get("BBB")); + assertEquals(new HashSet(Arrays.asList("AAA")), new HashSet(myMap.getAllKeysWithExistingMapping())); + + myMap.put("BBB", "BBB_VALUE"); + assertEquals("BBB_VALUE", myMap.get("BBB")); + assertEquals(new HashSet(Arrays.asList("AAA", "BBB")), new HashSet(myMap.getAllKeysWithExistingMapping())); + + myMap.put("AAA", "ANOTHER_AAA_VALUE"); + assertEquals("ANOTHER_AAA_VALUE", myMap.get("AAA")); + assertEquals(new HashSet(Arrays.asList("AAA", "BBB")), new HashSet(myMap.getAllKeysWithExistingMapping())); + + myMap.remove("AAA"); + assertNull(myMap.get("AAA")); + assertEquals("BBB_VALUE", myMap.get("BBB")); + assertEquals(new HashSet(Arrays.asList("BBB")), new HashSet(myMap.getAllKeysWithExistingMapping())); + + myMap.remove("BBB"); + assertNull(myMap.get("AAA")); + assertNull(myMap.get("BBB")); + assertEquals(new HashSet(), new HashSet(myMap.getAllKeysWithExistingMapping())); + + myMap.put("AAA", "FINAL_AAA_VALUE"); + assertEquals("FINAL_AAA_VALUE", myMap.get("AAA")); + assertNull(myMap.get("BBB")); + assertEquals(new HashSet(Arrays.asList("AAA")), new HashSet(myMap.getAllKeysWithExistingMapping())); + } + + public void testOpeningClosing() throws IOException { + List strings = new ArrayList(2000); + for (int i = 0; i < 2000; ++i) { + strings.add(createRandomString()); + } + for (int i = 0; i < 2000; ++i) { + final String key = strings.get(i); + myMap.put(key, key + "_value"); + myMap.close(); + myMap = new PersistentHashMap(myFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); + } + for (int i = 0; i < 2000; ++i) { + final String key = strings.get(i); + final String value = key + "_value"; + assertEquals(value, myMap.get(key)); + + myMap.put(key, value); + assertTrue(myMap.isDirty()); + + myMap.close(); + myMap = new PersistentHashMap(myFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); + } + for (int i = 0; i < 2000; ++i) { + assertTrue(!myMap.isDirty()); + myMap.close(); + myMap = new PersistentHashMap(myFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); + } + final String randomKey = createRandomString(); + myMap.put(randomKey, randomKey + "_value"); + assertTrue(myMap.isDirty()); + } + + public void testOpeningWithCompact() throws IOException { + final int stringsCount = 5/*1000000*/; + Set strings = new HashSet(stringsCount); + for (int i = 0; i < stringsCount; ++i) { + final String key = createRandomString(); + strings.add(key); + myMap.put(key, key + "_value"); + } + myMap.close(); + myMap = new PersistentHashMap(myFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); + + { // before compact + final Collection allKeys = new HashSet(myMap.getAllKeysWithExistingMapping()); + assertEquals(strings, allKeys); + for (String key : allKeys) { + final String val = myMap.get(key); + assertEquals(key + "_value", val); + } + } + myMap.compact(); + + { // after compact + final Collection allKeys = new HashSet(myMap.getAllKeysWithExistingMapping()); + assertEquals(strings, allKeys); + for (String key : allKeys) { + final String val = myMap.get(key); + assertEquals(key + "_value", val); + } + } + } + + public void testGarbageSizeUpdatedAfterCompact() throws IOException { + final int stringsCount = 5/*1000000*/; + Set strings = new HashSet(stringsCount); + for (int i = 0; i < stringsCount; ++i) { + final String key = createRandomString(); + strings.add(key); + myMap.put(key, key + "_value"); + } + + // create some garbage + for (String string : strings) { + myMap.remove(string); + } + strings.clear(); + + for (int i = 0; i < stringsCount; ++i) { + final String key = createRandomString(); + strings.add(key); + myMap.put(key, key + "_value"); + } + + myMap.close(); + + final int garbageSizeOnClose = myMap.getGarbageSize(); + + myMap = new PersistentHashMap(myFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); + + final int garbageSizeOnOpen = myMap.getGarbageSize(); + + assertEquals(garbageSizeOnClose, garbageSizeOnOpen); + + { // before compact + final Collection allKeys = new HashSet(myMap.getAllKeysWithExistingMapping()); + assertEquals(strings, allKeys); + for (String key : allKeys) { + final String val = myMap.get(key); + assertEquals(key + "_value", val); + } + } + + myMap.compact(); + + assertEquals(0, myMap.getGarbageSize()); + + myMap.close(); + myMap = new PersistentHashMap(myFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor()); + + final int garbageSizeAfterCompact = myMap.getGarbageSize(); + assertEquals(0, garbageSizeAfterCompact); + + { // after compact + final Collection allKeys = new HashSet(myMap.getAllKeysWithExistingMapping()); + assertEquals(strings, allKeys); + for (String key : allKeys) { + final String val = myMap.get(key); + assertEquals(key + "_value", val); + } + } + } + + public void testOpeningWithCompact2() throws IOException { + File file = FileUtil.createTempFile("persistent", "map"); + + PersistentHashMap map = new PersistentHashMap(file, new IntInlineKeyDescriptor(), new EnumeratorStringDescriptor()); + try { + final int stringsCount = 5/*1000000*/; + Map testMapping = new LinkedHashMap(stringsCount); + for (int i = 0; i < stringsCount; ++i) { + final String key = createRandomString(); + String value = key + "_value"; + testMapping.put(i, value); + map.put(i, value); + } + map.close(); + map = new PersistentHashMap(file, new IntInlineKeyDescriptor(), new EnumeratorStringDescriptor()); + + { // before compact + final Collection allKeys = new HashSet(map.getAllKeysWithExistingMapping()); + assertEquals(new HashSet(testMapping.keySet()), allKeys); + for (Integer key : allKeys) { + final String val = map.get(key); + assertEquals(testMapping.get(key), val); + } + } + map.compact(); + + { // after compact + final Collection allKeys = new HashSet(map.getAllKeysWithExistingMapping()); + assertEquals(new HashSet(testMapping.keySet()), allKeys); + for (Integer key : allKeys) { + final String val = map.get(key); + assertEquals(testMapping.get(key), val); + } + } + } + finally { + clearMap(file, map); + } + } + + public void testPerformance() throws IOException { + final IntObjectCache stringCache = new IntObjectCache(2000); + final IntObjectCache.DeletedPairsListener listener = new IntObjectCache.DeletedPairsListener() { + @Override + public void objectRemoved(final int key, final Object mapKey) { + try { + final String _mapKey = (String)mapKey; + assertEquals(myMap.enumerate(_mapKey), key); + + final String expectedMapValue = _mapKey == null ? null : _mapKey + "_value"; + final String actual = myMap.get(_mapKey); + assertEquals(expectedMapValue, actual); + + myMap.remove(_mapKey); + + assertNull(myMap.get(_mapKey)); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + + PlatformTestUtil.startPerformanceTest("Perforamnce", 9000, new ThrowableRunnable() { + @Override + public void run() throws Exception { + try { + stringCache.addDeletedPairsListener(listener); + for (int i = 0; i < 100000; ++i) { + final String string = createRandomString(); + final int id = myMap.enumerate(string); + stringCache.put(id, string); + myMap.put(string, string + "_value"); + } + stringCache.removeDeletedPairsListener(listener); + for (String key : stringCache) { + myMap.remove(key); + } + stringCache.removeAll(); + myMap.compact(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }).ioBound().assertTiming(); + + myMap.close(); + System.out.printf("File size = %d bytes\n", myFile.length()); + System.out + .printf("Data file size = %d bytes\n", new File(myDataFile.getParentFile(), myDataFile.getName() + Storage.DATA_EXTENSION).length()); + } + + public void testPerformance1() throws IOException { + final List strings = new ArrayList(2000); + for (int i = 0; i < 100000; ++i) { + strings.add(createRandomString()); + } + + PlatformTestUtil.startPerformanceTest("perf1",5000, new ThrowableRunnable() { + @Override + public void run() throws Exception { + for (int i = 0; i < 100000; ++i) { + final String string = strings.get(i); + myMap.put(string, string); + } + + for (int i = 0; i < 100000; ++i) { + final String string = createRandomString(); + myMap.get(string); + } + + for (int i = 0; i < 100000; ++i) { + final String string = createRandomString(); + myMap.remove(string); + } + + for (String string : strings) { + myMap.remove(string); + } + } + }).assertTiming(); + myMap.close(); + System.out.printf("File size = %d bytes\n", myFile.length()); + System.out + .printf("Data file size = %d bytes\n", new File(myDataFile.getParentFile(), myDataFile.getName() + Storage.DATA_EXTENSION).length()); + } + + private static String createRandomString() { + return StringEnumeratorTest.createRandomString(); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/util/io/StringEnumeratorTest.java b/platform/platform-tests/testSrc/com/intellij/util/io/StringEnumeratorTest.java new file mode 100644 index 000000000000..5d6c88b19d10 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/util/io/StringEnumeratorTest.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2006 JetBrains s.r.o. All Rights Reserved. + */ +package com.intellij.util.io; + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.util.ThrowableRunnable; +import com.intellij.util.containers.IntObjectCache; +import junit.framework.TestCase; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class StringEnumeratorTest extends TestCase { + private static final String COLLISION_1 = ""; + private static final String COLLISION_2 = "\u0000"; + private static final String UTF_1 = "\ue534"; + private static final String UTF_2 = + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + + private PersistentStringEnumerator myEnumerator; + private File myFile; + + @Override + protected void setUp() throws Exception { + super.setUp(); + myFile = FileUtil.createTempFile("persistent", "trie"); + myEnumerator = new PersistentStringEnumerator(myFile); + } + + @Override + protected void tearDown() throws Exception { + myEnumerator.close(); + FileUtil.delete(myFile); + FileUtil.delete(new File(myFile.getParentFile(), myFile.getName() + ".len")); + assertTrue(!myFile.exists()); + super.tearDown(); + } + + public void testAddEqualStrings() throws IOException { + final int index = myEnumerator.enumerate("IntelliJ IDEA"); + myEnumerator.enumerate("Just another string"); + assertEquals(index, myEnumerator.enumerate("IntelliJ IDEA")); + } + + public void testAddEqualStringsAndMuchGarbage() throws IOException { + final Set stringsAded = new HashSet(); + final int index = myEnumerator.enumerate("IntelliJ IDEA"); + stringsAded.add("IntelliJ IDEA"); + // clear strings and nodes cache + for (int i = 0; i < 20000; ++i) { + final String v = Integer.toString(i) + "Just another string"; + stringsAded.add(v); + final int idx = myEnumerator.enumerate(v); + assertEquals(v, myEnumerator.valueOf(idx)); + } + + assertEquals(index, myEnumerator.enumerate("IntelliJ IDEA")); + final Set enumerated = new HashSet(myEnumerator.getAllDataObjects(null)); + assertEquals(stringsAded, enumerated); + } + + public void testCollision() throws Exception { + int id1 = myEnumerator.enumerate(COLLISION_1); + int id2 = myEnumerator.enumerate(COLLISION_2); + assertFalse(id1 == id2); + + assertEquals(COLLISION_1, myEnumerator.valueOf(id1)); + assertEquals(COLLISION_2, myEnumerator.valueOf(id2)); + assertEquals(new HashSet(Arrays.asList(COLLISION_1, COLLISION_2)), new HashSet(myEnumerator.getAllDataObjects(null))); + } + + public void testCollision1() throws Exception { + int id1 = myEnumerator.enumerate(COLLISION_1); + + assertEquals(id1, myEnumerator.tryEnumerate(COLLISION_1)); + assertEquals(PersistentEnumerator.NULL_ID, myEnumerator.tryEnumerate(COLLISION_2)); + + int id2 = myEnumerator.enumerate(COLLISION_2); + assertFalse(id1 == id2); + + assertEquals(id1, myEnumerator.tryEnumerate(COLLISION_1)); + assertEquals(id2, myEnumerator.tryEnumerate(COLLISION_2)); + assertEquals(PersistentEnumerator.NULL_ID, myEnumerator.tryEnumerate("some string")); + + assertEquals(COLLISION_1, myEnumerator.valueOf(id1)); + assertEquals(COLLISION_2, myEnumerator.valueOf(id2)); + assertEquals(new HashSet(Arrays.asList(COLLISION_1, COLLISION_2)), new HashSet(myEnumerator.getAllDataObjects(null))); + } + + + public void testUTFString() throws Exception { + int id1 = myEnumerator.enumerate(UTF_1); + int id2 = myEnumerator.enumerate(UTF_2); + assertFalse(id1 == id2); + + assertEquals(UTF_1, myEnumerator.valueOf(id1)); + assertEquals(UTF_2, myEnumerator.valueOf(id2)); + assertEquals(new HashSet(Arrays.asList(UTF_1, UTF_2)), new HashSet(myEnumerator.getAllDataObjects(null))); + } + + public void testOpeningClosing() throws IOException { + ArrayList strings = new ArrayList(2000); + for (int i = 0; i < 2000; ++i) { + strings.add(createRandomString()); + } + for (int i = 0; i < 2000; ++i) { + myEnumerator.enumerate(strings.get(i)); + myEnumerator.close(); + myEnumerator = new PersistentStringEnumerator(myFile); + } + for (int i = 0; i < 2000; ++i) { + myEnumerator.enumerate(strings.get(i)); + assertTrue(!myEnumerator.isDirty()); + myEnumerator.close(); + myEnumerator = new PersistentStringEnumerator(myFile); + } + for (int i = 0; i < 2000; ++i) { + assertTrue(!myEnumerator.isDirty()); + myEnumerator.close(); + myEnumerator = new PersistentStringEnumerator(myFile); + } + final HashSet allStringsSet = new HashSet(strings); + assertEquals(allStringsSet, new HashSet(myEnumerator.getAllDataObjects(null))); + + final String additionalString = createRandomString(); + allStringsSet.add(additionalString); + myEnumerator.enumerate(additionalString); + assertTrue(myEnumerator.isDirty()); + assertEquals(allStringsSet, new HashSet(myEnumerator.getAllDataObjects(null))); + } + + public void testPerformance() throws IOException { + final IntObjectCache stringCache = new IntObjectCache(2000); + final IntObjectCache.DeletedPairsListener listener = new IntObjectCache.DeletedPairsListener() { + @Override + public void objectRemoved(final int key, final Object value) { + try { + assertEquals(myEnumerator.enumerate((String)value), key); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + + PlatformTestUtil.startPerformanceTest("PersistentStringEnumerator performance failed", 2500, new ThrowableRunnable() { + @Override + public void run() throws Exception { + stringCache.addDeletedPairsListener(listener); + for (int i = 0; i < 100000; ++i) { + final String string = createRandomString(); + stringCache.cacheObject(myEnumerator.enumerate(string), string); + } + stringCache.removeDeletedPairsListener(listener); + stringCache.removeAll(); + } + }).cpuBound().assertTiming(); + myEnumerator.close(); + System.out.printf("File size = %d bytes\n", myFile.length()); + } + + private static final StringBuilder builder = new StringBuilder(100); + private static final Random random = new Random(); + + static String createRandomString() { + builder.setLength(0); + int len = random.nextInt(40) + 10; + for (int i = 0; i < len; ++i) { + builder.append((char)(32 + random.nextInt(2 + i >> 1))); + } + return builder.toString(); + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/util/ui/update/MergingUpdateQueueTest.java b/platform/platform-tests/testSrc/com/intellij/util/ui/update/MergingUpdateQueueTest.java new file mode 100644 index 000000000000..d6ac3110711e --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/util/ui/update/MergingUpdateQueueTest.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package com.intellij.util.ui.update; + +import com.intellij.testFramework.FlyIdeaTestCase; +import com.intellij.util.WaitFor; + +public class MergingUpdateQueueTest extends FlyIdeaTestCase { + public void testOnShowNotify() throws Exception { + final MyUpdate first = new MyUpdate("first"); + final MyUpdate second = new MyUpdate("second"); + + final MyQueue queue = new MyQueue(); + + queue.queue(first); + queue.queue(second); + + assertFalse(first.isExecuted()); + assertFalse(second.isExecuted()); + + queue.showNotify(); + + waitForExecution(queue); + + assertAfterProcessing(first, true, true); + assertAfterProcessing(second, true, true); + } + + public void testPriority() throws Exception { + final boolean attemps[] = new boolean[3]; + + final MyQueue queue = new MyQueue(); + + final MyUpdate first = new MyUpdate("addedFirstButRunLast") { // default priority is 999 + @Override + public void run() { + super.run(); + attemps[0] = true; + assertTrue(attemps[1]); + assertTrue(attemps[2]); + } + }; + + final MyUpdate second = new MyUpdate("addedSecondButRunFirst", Update.HIGH_PRIORITY) { + @Override + public void run() { + super.run(); + assertFalse(attemps[0]); + attemps[1] = true; + assertFalse(attemps[2]); + } + }; + + final MyUpdate third = new MyUpdate("addedThirdButRunSecond", 100) { + @Override + public void run() { + super.run(); + assertFalse(attemps[0]); + assertTrue(attemps[1]); + attemps[2] = true; + } + }; + + queue.queue(first); + queue.queue(second); + queue.queue(third); + + waitForExecution(queue); + + assertAfterProcessing(first, true, true); + assertAfterProcessing(second, true, true); + assertAfterProcessing(third, true, true); + } + + public void testDoNoExecuteExpired() throws Throwable { + + final boolean[] expired = new boolean[1]; + + final MyUpdate first = new MyUpdate("first") { + @Override + public boolean isExpired() { + return expired[0]; + } + }; + final MyUpdate second = new MyUpdate("second"); + + final MyQueue queue = new MyQueue(); + + queue.queue(first); + queue.queue(second); + + assertFalse(first.isExecuted()); + assertFalse(second.isExecuted()); + + expired[0] = true; + + queue.showNotify(); + waitForExecution(queue); + + assertAfterProcessing(first, false, true); + assertAfterProcessing(second, true, true); + } + + + public void testOnShowNotifyMerging() throws Exception { + final MyUpdate twin1 = new MyUpdate("twin"); + final MyUpdate twin2 = new MyUpdate("twin"); + + final MyQueue queue = new MyQueue(); + + queue.queue(twin1); + queue.queue(twin2); + + assertFalse(twin1.isExecuted()); + assertFalse(twin2.isExecuted()); + + queue.showNotify(); + waitForExecution(queue); + + assertAfterProcessing(twin1, false, true); + assertAfterProcessing(twin2, true, true); + } + + public void testExecuteWhenActive() throws Exception { + final MyQueue queue = new MyQueue(); + + queue.showNotify(); + + final MyUpdate first = new MyUpdate("first"); + final MyUpdate second = new MyUpdate("second"); + + queue.queue(first); + queue.queue(second); + + waitForExecution(queue); + + assertAfterProcessing(first, true, true); + assertAfterProcessing(second, true, true); + } + + public void testMergeWhenActive() throws Exception { + final MyQueue queue = new MyQueue(); + + queue.showNotify(); + + final MyUpdate twin1 = new MyUpdate("twin"); + final MyUpdate twin2 = new MyUpdate("twin"); + + queue.queue(twin1); + queue.queue(twin2); + + waitForExecution(queue); + + assertAfterProcessing(twin1, false, true); + assertAfterProcessing(twin2, true, true); + } + + public void testEatByQueue() throws Exception { + executeEatingTest(false); + } + + public void testEatUpdatesInQueue() throws Exception { + executeEatingTest(true); + } + + private void executeEatingTest(boolean foodFirst) throws Exception{ + final MyQueue queue = new MyQueue(); + queue.showNotify(); + + final MyUpdate food = new MyUpdate("food"); + MyUpdate hungry = new MyUpdate("hungry") { + @Override + public boolean canEat(Update update) { + return update == food; + } + }; + + if (foodFirst) { + queue.queue(food); + queue.queue(hungry); + } else { + queue.queue(hungry); + queue.queue(food); + } + + waitForExecution(queue); + + assertAfterProcessing(hungry, true, true); + assertAfterProcessing(food, false, false); + } + + public void testCuncurrentFlushing() throws Exception { + final MyQueue queue = new MyQueue(); + queue.showNotify(); + + queue.queue(new MyUpdate("update") { + @Override + public boolean isExpired() { + queue.flush(); + return false; + } + }); + + waitForExecution(queue); + } + + public void testConcurrentQueing() throws Exception { + final MyQueue queue = new MyQueue(); + queue.showNotify(); + + queue.queue(new MyUpdate("update") { + @Override + public boolean isExpired() { + queue.queue(new MyUpdate("update again")); + return false; + } + }); + + waitForExecution(queue); + } + + + private void assertAfterProcessing(MyUpdate update, boolean shouldBeExecuted, boolean shouldBeProcessed) { + assertEquals(shouldBeExecuted, update.isExecuted()); + assertEquals(shouldBeProcessed, update.wasProcessed()); + } + + private static class MyUpdate extends Update { + + private boolean myExecuted; + + MyUpdate(String s) { + super(s); + } + + MyUpdate(Object identity, int priority) { + super(identity, priority); + } + + @Override + public void run() { + myExecuted = true; + } + + public boolean isExecuted() { + return myExecuted; + } + } + + private static class MyQueue extends MergingUpdateQueue { + private boolean myExecuted; + + MyQueue() { + super("Test", 400, false, null); + setPassThrough(false); + } + + @Override + public void run() { + + } + + public void onTimer() { + super.run(); + } + + @Override + protected void execute(final Update[] update) { + super.execute(update); + myExecuted = true; + } + + public boolean wasExecuted() { + return myExecuted; + } + + @Override + protected boolean isModalityStateCorrect() { + return true; + } + } + + private void waitForExecution(final MyQueue queue) { + queue.onTimer(); + new WaitFor(5000) { + @Override + protected boolean condition() { + return queue.wasExecuted(); + } + }; + } + +}