/******************************************************************************* * Copyright (c) 2004, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * James Blackburn (Broadcom Corp.) - ongoing development * Alexander Kurtakov <akurtako@redhat.com> - Bug 459343 *******************************************************************************/ package org.eclipse.core.tests.internal.localstore; import java.io.*; import java.util.*; import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.core.internal.localstore.Bucket; import org.eclipse.core.internal.localstore.BucketTree; import org.eclipse.core.internal.resources.Workspace; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.core.tests.resources.ResourceTest; public class BucketTreeTests extends ResourceTest { static class SimpleBucket extends Bucket { static class SimpleEntry extends Entry { private Map<String, String> value; public SimpleEntry(IPath path, Map<String, String> value) { super(path); this.value = value; } @Override public int getOccurrences() { return value.size(); } public String getProperty(String key) { return value.get(key); } @Override public Object getValue() { return value; } } public SimpleBucket() { super(); } @Override protected String getIndexFileName() { return "simple_bucket.index"; } @Override protected String getVersionFileName() { return "simple_bucket.version"; } @Override @SuppressWarnings("unchecked") protected Entry createEntry(IPath path, Object value) { return new SimpleEntry(path, (Map<String, String>) value); } @Override protected byte getVersion() { return 0; } @Override protected Object readEntryValue(DataInputStream source) throws IOException { int length = source.readUnsignedShort(); Map<String, String> value = new HashMap<>(length); for (int j = 0; j < length; j++) { value.put(source.readUTF(), source.readUTF()); } return value; } public void set(IPath path, String key, String value) { String pathAsString = path.toString(); @SuppressWarnings("unchecked") Map<String, String> existing = (Map<String, String>) getEntryValue(pathAsString); if (existing == null) { if (value != null) { existing = new HashMap<>(); existing.put(key, value); setEntryValue(pathAsString, existing); } return; } if (value == null) { existing.remove(key); if (existing.isEmpty()) { existing = null; } } else { existing.put(key, value); } setEntryValue(pathAsString, existing); } @Override protected void writeEntryValue(DataOutputStream destination, Object entryValue) throws IOException { @SuppressWarnings("unchecked") Map<String, String> value = (Map<String, String>) entryValue; int length = value.size(); destination.writeShort(length); for (Map.Entry<String, String> entry : value.entrySet()) { destination.writeUTF(entry.getKey()); destination.writeUTF(entry.getValue()); } } } public static Test suite() { return new TestSuite(BucketTreeTests.class); } public BucketTreeTests(String name) { super(name); } public void testVisitor() { IPath baseLocation = getRandomLocation(); try { // keep the reference around - it is the same returned by tree.getCurrent() SimpleBucket bucket = new SimpleBucket(); BucketTree tree = new BucketTree((Workspace) getWorkspace(), bucket); IProject proj1 = getWorkspace().getRoot().getProject("proj1"); IProject proj2 = getWorkspace().getRoot().getProject("proj2"); IFile file1 = proj1.getFile("file1.txt"); IFolder folder1 = proj1.getFolder("folder1"); IFile file2 = folder1.getFile("file2.txt"); ensureExistsInWorkspace(new IResource[] {file1, file2, proj2}, true); IPath[] paths = {Path.ROOT, proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath(), file2.getFullPath(), proj2.getFullPath()}; for (int i = 0; i < paths.length; i++) { try { tree.loadBucketFor(paths[i]); } catch (CoreException e) { fail("0.1." + i, e); } bucket.set(paths[i], "path", paths[i].toString()); bucket.set(paths[i], "segments", Integer.toString(paths[i].segmentCount())); } try { bucket.save(); } catch (CoreException e) { fail("0.2", e); } verify(tree, "1.1", Path.ROOT, BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {Path.ROOT})); verify(tree, "1.2", Path.ROOT, BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {Path.ROOT, proj1.getFullPath(), proj2.getFullPath()})); verify(tree, "1.3", Path.ROOT, BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {Path.ROOT, proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath(), file2.getFullPath(), proj2.getFullPath()})); verify(tree, "2.1", proj1.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {proj1.getFullPath()})); verify(tree, "2.2", proj1.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath()})); verify(tree, "2.3", proj1.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {proj1.getFullPath(), file1.getFullPath(), folder1.getFullPath(), file2.getFullPath()})); verify(tree, "3.1", file1.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {file1.getFullPath()})); verify(tree, "3.2", file1.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {file1.getFullPath()})); verify(tree, "3.3", file1.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {file1.getFullPath()})); verify(tree, "4.1", folder1.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {folder1.getFullPath()})); verify(tree, "4.2", folder1.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {folder1.getFullPath(), file2.getFullPath()})); verify(tree, "4.3", folder1.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {folder1.getFullPath(), file2.getFullPath()})); verify(tree, "5.1", file2.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {file2.getFullPath()})); verify(tree, "5.2", file2.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {file2.getFullPath()})); verify(tree, "5.3", file2.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {file2.getFullPath()})); verify(tree, "6.1", proj2.getFullPath(), BucketTree.DEPTH_ZERO, Arrays.asList(new IPath[] {proj2.getFullPath()})); verify(tree, "6.2", proj2.getFullPath(), BucketTree.DEPTH_ONE, Arrays.asList(new IPath[] {proj2.getFullPath()})); verify(tree, "6.3", proj2.getFullPath(), BucketTree.DEPTH_INFINITE, Arrays.asList(new IPath[] {proj2.getFullPath()})); } finally { ensureDoesNotExistInFileSystem(baseLocation.toFile()); } } public void verify(BucketTree tree, final String tag, IPath root, int depth, final Collection<IPath> expected) { final Set<IPath> visited = new HashSet<>(); SimpleBucket.Visitor verifier = new SimpleBucket.Visitor() { @Override public int visit(org.eclipse.core.internal.localstore.Bucket.Entry entry) { SimpleBucket.SimpleEntry simple = (SimpleBucket.SimpleEntry) entry; IPath path = simple.getPath(); assertTrue(tag + ".0 " + path, expected.contains(path)); visited.add(path); assertEquals(tag + ".1 " + path, path.toString(), simple.getProperty("path")); assertEquals(tag + ".2 " + path, Integer.toString(path.segmentCount()), simple.getProperty("segments")); return CONTINUE; } }; try { tree.accept(verifier, root, depth); } catch (CoreException e) { fail(tag + ".3", e); } assertEquals(tag + ".4", expected.size(), visited.size()); for (IPath path : expected) { assertTrue(tag + ".5 " + path, visited.contains(path)); } } }