diff options
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/vfs/PathFragmentTest.java')
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/vfs/PathFragmentTest.java | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/PathFragmentTest.java b/src/test/java/com/google/devtools/build/lib/vfs/PathFragmentTest.java new file mode 100644 index 0000000000..9ab9bfa9f3 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/vfs/PathFragmentTest.java @@ -0,0 +1,481 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// 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.google.devtools.build.lib.vfs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.testing.EqualsTester; +import com.google.devtools.build.lib.testutil.MoreAsserts; +import com.google.devtools.build.lib.testutil.TestUtils; +import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +/** + * This class tests the functionality of the PathFragment. + */ +@RunWith(JUnit4.class) +public class PathFragmentTest { + @Test + public void testMergeFourPathsWithAbsolute() { + assertEquals(new PathFragment("x/y/z/a/b/c/d/e"), + new PathFragment(new PathFragment("x/y"), new PathFragment("z/a"), + new PathFragment("/b/c"), // absolute! + new PathFragment("d/e"))); + } + + @Test + public void testEqualsAndHashCode() { + InMemoryFileSystem filesystem = new InMemoryFileSystem(); + + new EqualsTester() + .addEqualityGroup(new PathFragment("../relative/path"), + new PathFragment("../relative/path"), + new PathFragment(new File("../relative/path"))) + .addEqualityGroup(new PathFragment("something/else")) + .addEqualityGroup(new PathFragment("/something/else")) + .addEqualityGroup(new PathFragment("/"), + new PathFragment("//////")) + .addEqualityGroup(new PathFragment("")) + .addEqualityGroup(filesystem.getRootDirectory()) // A Path object. + .testEquals(); + } + + @Test + public void testHashCodeCache() { + PathFragment relativePath = new PathFragment("../relative/path"); + PathFragment rootPath = new PathFragment("/"); + + int oldResult = relativePath.hashCode(); + int rootResult = rootPath.hashCode(); + assertEquals(oldResult, relativePath.hashCode()); + assertEquals(rootResult, rootPath.hashCode()); + } + + private void checkRelativeTo(String path, String base) { + PathFragment relative = new PathFragment(path).relativeTo(base); + assertEquals(new PathFragment(path), new PathFragment(base).getRelative(relative).normalize()); + } + + @Test + public void testRelativeTo() { + assertPath("bar/baz", new PathFragment("foo/bar/baz").relativeTo("foo")); + assertPath("bar/baz", new PathFragment("/foo/bar/baz").relativeTo("/foo")); + assertPath("baz", new PathFragment("foo/bar/baz").relativeTo("foo/bar")); + assertPath("baz", new PathFragment("/foo/bar/baz").relativeTo("/foo/bar")); + assertPath("foo", new PathFragment("/foo").relativeTo("/")); + assertPath("foo", new PathFragment("foo").relativeTo("")); + assertPath("foo/bar", new PathFragment("foo/bar").relativeTo("")); + + checkRelativeTo("foo/bar/baz", "foo"); + checkRelativeTo("/foo/bar/baz", "/foo"); + checkRelativeTo("foo/bar/baz", "foo/bar"); + checkRelativeTo("/foo/bar/baz", "/foo/bar"); + checkRelativeTo("/foo", "/"); + checkRelativeTo("foo", ""); + checkRelativeTo("foo/bar", ""); + } + + @Test + public void testIsAbsolute() { + assertTrue(new PathFragment("/absolute/test").isAbsolute()); + assertFalse(new PathFragment("relative/test").isAbsolute()); + assertTrue(new PathFragment(new File("/absolute/test")).isAbsolute()); + assertFalse(new PathFragment(new File("relative/test")).isAbsolute()); + } + + @Test + public void testIsNormalized() { + assertTrue(new PathFragment("/absolute/path").isNormalized()); + assertTrue(new PathFragment("some//path").isNormalized()); + assertFalse(new PathFragment("some/./path").isNormalized()); + assertFalse(new PathFragment("../some/path").isNormalized()); + assertFalse(new PathFragment("some/other/../path").isNormalized()); + assertTrue(new PathFragment("some/other//tricky..path..").isNormalized()); + assertTrue(new PathFragment("/some/other//tricky..path..").isNormalized()); + } + + @Test + public void testRootNodeReturnsRootString() { + PathFragment rootFragment = new PathFragment("/"); + assertEquals("/", rootFragment.getPathString()); + } + + @Test + public void testGetPathFragmentDoesNotNormalize() { + String nonCanonicalPath = "/a/weird/noncanonical/../path/."; + assertEquals(nonCanonicalPath, + new PathFragment(nonCanonicalPath).getPathString()); + } + + @Test + public void testGetRelative() { + assertEquals("a/b", new PathFragment("a").getRelative("b").getPathString()); + assertEquals("a/b/c/d", new PathFragment("a/b").getRelative("c/d").getPathString()); + assertEquals("/a/b", new PathFragment("c/d").getRelative("/a/b").getPathString()); + assertEquals("a", new PathFragment("a").getRelative("").getPathString()); + assertEquals("/", new PathFragment("/").getRelative("").getPathString()); + } + + @Test + public void testGetChildWorks() { + PathFragment pf = new PathFragment("../some/path"); + assertEquals(new PathFragment("../some/path/hi"), pf.getChild("hi")); + } + + @Test + public void testGetChildRejectsInvalidBaseNames() { + PathFragment pf = new PathFragment("../some/path"); + assertGetChildFails(pf, "."); + assertGetChildFails(pf, ".."); + assertGetChildFails(pf, "x/y"); + assertGetChildFails(pf, "/y"); + assertGetChildFails(pf, "y/"); + assertGetChildFails(pf, ""); + } + + private void assertGetChildFails(PathFragment pf, String baseName) { + try { + pf.getChild(baseName); + fail(); + } catch (Exception e) { /* Expected. */ } + } + + // Tests after here test the canonicalization + private void assertRegular(String expected, String actual) { + assertEquals(expected, new PathFragment(actual).getPathString()); // compare string forms + assertEquals(new PathFragment(expected), new PathFragment(actual)); // compare fragment forms + } + + @Test + public void testEmptyPathToEmptyPath() { + assertRegular("/", "/"); + assertRegular("", ""); + } + + @Test + public void testRedundantSlashes() { + assertRegular("/", "///"); + assertRegular("/foo/bar", "/foo///bar"); + assertRegular("/foo/bar", "////foo//bar"); + } + + @Test + public void testSimpleNameToSimpleName() { + assertRegular("/foo", "/foo"); + assertRegular("foo", "foo"); + } + + @Test + public void testSimplePathToSimplePath() { + assertRegular("/foo/bar", "/foo/bar"); + assertRegular("foo/bar", "foo/bar"); + } + + @Test + public void testStripsTrailingSlash() { + assertRegular("/foo/bar", "/foo/bar/"); + } + + @Test + public void testGetParentDirectory() { + PathFragment fooBarWiz = new PathFragment("foo/bar/wiz"); + PathFragment fooBar = new PathFragment("foo/bar"); + PathFragment foo = new PathFragment("foo"); + PathFragment empty = new PathFragment(""); + assertEquals(fooBar, fooBarWiz.getParentDirectory()); + assertEquals(foo, fooBar.getParentDirectory()); + assertEquals(empty, foo.getParentDirectory()); + assertNull(empty.getParentDirectory()); + + PathFragment fooBarWizAbs = new PathFragment("/foo/bar/wiz"); + PathFragment fooBarAbs = new PathFragment("/foo/bar"); + PathFragment fooAbs = new PathFragment("/foo"); + PathFragment rootAbs = new PathFragment("/"); + assertEquals(fooBarAbs, fooBarWizAbs.getParentDirectory()); + assertEquals(fooAbs, fooBarAbs.getParentDirectory()); + assertEquals(rootAbs, fooAbs.getParentDirectory()); + assertNull(rootAbs.getParentDirectory()); + + // Note, this is surprising but correct behavior: + assertEquals(fooBarAbs, + new PathFragment("/foo/bar/..").getParentDirectory()); + } + + @Test + public void testSegmentsCount() { + assertEquals(2, new PathFragment("foo/bar").segmentCount()); + assertEquals(2, new PathFragment("/foo/bar").segmentCount()); + assertEquals(2, new PathFragment("foo//bar").segmentCount()); + assertEquals(2, new PathFragment("/foo//bar").segmentCount()); + assertEquals(1, new PathFragment("foo/").segmentCount()); + assertEquals(1, new PathFragment("/foo/").segmentCount()); + assertEquals(1, new PathFragment("foo").segmentCount()); + assertEquals(1, new PathFragment("/foo").segmentCount()); + assertEquals(0, new PathFragment("/").segmentCount()); + assertEquals(0, new PathFragment("").segmentCount()); + } + + + @Test + public void testGetSegment() { + assertEquals("foo", new PathFragment("foo/bar").getSegment(0)); + assertEquals("bar", new PathFragment("foo/bar").getSegment(1)); + assertEquals("foo", new PathFragment("/foo/bar").getSegment(0)); + assertEquals("bar", new PathFragment("/foo/bar").getSegment(1)); + assertEquals("foo", new PathFragment("foo/").getSegment(0)); + assertEquals("foo", new PathFragment("/foo/").getSegment(0)); + assertEquals("foo", new PathFragment("foo").getSegment(0)); + assertEquals("foo", new PathFragment("/foo").getSegment(0)); + } + + @Test + public void testBasename() throws Exception { + assertEquals("bar", new PathFragment("foo/bar").getBaseName()); + assertEquals("bar", new PathFragment("/foo/bar").getBaseName()); + assertEquals("foo", new PathFragment("foo/").getBaseName()); + assertEquals("foo", new PathFragment("/foo/").getBaseName()); + assertEquals("foo", new PathFragment("foo").getBaseName()); + assertEquals("foo", new PathFragment("/foo").getBaseName()); + assertEquals("", new PathFragment("/").getBaseName()); + assertEquals("", new PathFragment("").getBaseName()); + } + + private static void assertPath(String expected, PathFragment actual) { + assertEquals(expected, actual.getPathString()); + } + + @Test + public void testReplaceName() throws Exception { + assertPath("foo/baz", new PathFragment("foo/bar").replaceName("baz")); + assertPath("/foo/baz", new PathFragment("/foo/bar").replaceName("baz")); + assertPath("foo", new PathFragment("foo/bar").replaceName("")); + assertPath("baz", new PathFragment("foo/").replaceName("baz")); + assertPath("/baz", new PathFragment("/foo/").replaceName("baz")); + assertPath("baz", new PathFragment("foo").replaceName("baz")); + assertPath("/baz", new PathFragment("/foo").replaceName("baz")); + assertEquals(null, new PathFragment("/").replaceName("baz")); + assertEquals(null, new PathFragment("/").replaceName("")); + assertEquals(null, new PathFragment("").replaceName("baz")); + assertEquals(null, new PathFragment("").replaceName("")); + + assertPath("foo/bar/baz", new PathFragment("foo/bar").replaceName("bar/baz")); + assertPath("foo/bar/baz", new PathFragment("foo/bar").replaceName("bar/baz/")); + + // Absolute path arguments will clobber the original path. + assertPath("/absolute", new PathFragment("foo/bar").replaceName("/absolute")); + assertPath("/", new PathFragment("foo/bar").replaceName("/")); + } + @Test + public void testSubFragment() throws Exception { + assertPath("/foo/bar/baz", + new PathFragment("/foo/bar/baz").subFragment(0, 3)); + assertPath("foo/bar/baz", + new PathFragment("foo/bar/baz").subFragment(0, 3)); + assertPath("/foo/bar", + new PathFragment("/foo/bar/baz").subFragment(0, 2)); + assertPath("bar/baz", + new PathFragment("/foo/bar/baz").subFragment(1, 3)); + assertPath("/foo", + new PathFragment("/foo/bar/baz").subFragment(0, 1)); + assertPath("bar", + new PathFragment("/foo/bar/baz").subFragment(1, 2)); + assertPath("baz", new PathFragment("/foo/bar/baz").subFragment(2, 3)); + assertPath("/", new PathFragment("/foo/bar/baz").subFragment(0, 0)); + assertPath("", new PathFragment("foo/bar/baz").subFragment(0, 0)); + assertPath("", new PathFragment("foo/bar/baz").subFragment(1, 1)); + try { + fail("unexpectedly succeeded: " + new PathFragment("foo/bar/baz").subFragment(3, 2)); + } catch (IndexOutOfBoundsException e) { /* Expected. */ } + try { + fail("unexpectedly succeeded: " + new PathFragment("foo/bar/baz").subFragment(4, 4)); + } catch (IndexOutOfBoundsException e) { /* Expected. */ } + } + + @Test + public void testStartsWith() { + PathFragment foobar = new PathFragment("/foo/bar"); + PathFragment foobarRelative = new PathFragment("foo/bar"); + + // (path, prefix) => true + assertTrue(foobar.startsWith(foobar)); + assertTrue(foobar.startsWith(new PathFragment("/"))); + assertTrue(foobar.startsWith(new PathFragment("/foo"))); + assertTrue(foobar.startsWith(new PathFragment("/foo/"))); + assertTrue(foobar.startsWith(new PathFragment("/foo/bar/"))); // Includes trailing slash. + + // (prefix, path) => false + assertFalse(new PathFragment("/foo").startsWith(foobar)); + assertFalse(new PathFragment("/").startsWith(foobar)); + + // (absolute, relative) => false + assertFalse(foobar.startsWith(foobarRelative)); + assertFalse(foobarRelative.startsWith(foobar)); + + // (relative path, relative prefix) => true + assertTrue(foobarRelative.startsWith(foobarRelative)); + assertTrue(foobarRelative.startsWith(new PathFragment("foo"))); + assertTrue(foobarRelative.startsWith(new PathFragment(""))); + + // (path, sibling) => false + assertFalse(new PathFragment("/foo/wiz").startsWith(foobar)); + assertFalse(foobar.startsWith(new PathFragment("/foo/wiz"))); + + // Does not normalize. + PathFragment foodotbar = new PathFragment("foo/./bar"); + assertTrue(foodotbar.startsWith(foodotbar)); + assertTrue(foodotbar.startsWith(new PathFragment("foo/."))); + assertTrue(foodotbar.startsWith(new PathFragment("foo/./"))); + assertTrue(foodotbar.startsWith(new PathFragment("foo/./bar"))); + assertFalse(foodotbar.startsWith(new PathFragment("foo/bar"))); + } + + @Test + public void testEndsWith() { + PathFragment foobar = new PathFragment("/foo/bar"); + PathFragment foobarRelative = new PathFragment("foo/bar"); + + // (path, suffix) => true + assertTrue(foobar.endsWith(foobar)); + assertTrue(foobar.endsWith(new PathFragment("bar"))); + assertTrue(foobar.endsWith(new PathFragment("foo/bar"))); + assertTrue(foobar.endsWith(new PathFragment("/foo/bar"))); + assertFalse(foobar.endsWith(new PathFragment("/bar"))); + + // (prefix, path) => false + assertFalse(new PathFragment("/foo").endsWith(foobar)); + assertFalse(new PathFragment("/").endsWith(foobar)); + + // (suffix, path) => false + assertFalse(new PathFragment("/bar").endsWith(foobar)); + assertFalse(new PathFragment("bar").endsWith(foobar)); + assertFalse(new PathFragment("").endsWith(foobar)); + + // (absolute, relative) => true + assertTrue(foobar.endsWith(foobarRelative)); + + // (relative, absolute) => false + assertFalse(foobarRelative.endsWith(foobar)); + + // (relative path, relative prefix) => true + assertTrue(foobarRelative.endsWith(foobarRelative)); + assertTrue(foobarRelative.endsWith(new PathFragment("bar"))); + assertTrue(foobarRelative.endsWith(new PathFragment(""))); + + // (path, sibling) => false + assertFalse(new PathFragment("/foo/wiz").endsWith(foobar)); + assertFalse(foobar.endsWith(new PathFragment("/foo/wiz"))); + } + + static List<PathFragment> toPaths(List<String> strs) { + List<PathFragment> paths = Lists.newArrayList(); + for (String s : strs) { + paths.add(new PathFragment(s)); + } + return paths; + } + + @Test + public void testCompareTo() throws Exception { + List<String> pathStrs = ImmutableList.of( + "", "/", "//", ".", "/./", "foo/.//bar", "foo", "/foo", "foo/bar", "foo/Bar", "Foo/bar"); + List<PathFragment> paths = toPaths(pathStrs); + // First test that compareTo is self-consistent. + for (PathFragment x : paths) { + for (PathFragment y : paths) { + for (PathFragment z : paths) { + // Anti-symmetry + assertEquals(Integer.signum(x.compareTo(y)), + -1 * Integer.signum(y.compareTo(x))); + // Transitivity + if (x.compareTo(y) > 0 && y.compareTo(z) > 0) { + MoreAsserts.assertGreaterThan(0, x.compareTo(z)); + } + // "Substitutability" + if (x.compareTo(y) == 0) { + assertEquals(Integer.signum(x.compareTo(z)), Integer.signum(y.compareTo(z))); + } + // Consistency with equals + assertEquals((x.compareTo(y) == 0), x.equals(y)); + } + } + } + // Now test that compareTo does what we expect. The exact ordering here doesn't matter much, + // but there are three things to notice: 1. absolute < relative, 2. comparison is lexicographic + // 3. repeated slashes are ignored. (PathFragment("//") prints as "/"). + Collections.shuffle(paths); + Collections.sort(paths); + List<PathFragment> expectedOrder = toPaths(ImmutableList.of( + "/", "//", "/./", "/foo", "", ".", "Foo/bar", "foo", "foo/.//bar", "foo/Bar", "foo/bar")); + assertEquals(expectedOrder, paths); + } + + @Test + public void testGetSafePathString() { + assertEquals("/", new PathFragment("/").getSafePathString()); + assertEquals("/abc", new PathFragment("/abc").getSafePathString()); + assertEquals(".", new PathFragment("").getSafePathString()); + assertEquals(".", PathFragment.EMPTY_FRAGMENT.getSafePathString()); + assertEquals("abc/def", new PathFragment("abc/def").getSafePathString()); + } + + @Test + public void testNormalize() { + assertEquals(new PathFragment("/a/b"), new PathFragment("/a/b").normalize()); + assertEquals(new PathFragment("/a/b"), new PathFragment("/a/./b").normalize()); + assertEquals(new PathFragment("/b"), new PathFragment("/a/../b").normalize()); + assertEquals(new PathFragment("a/b"), new PathFragment("a/b").normalize()); + assertEquals(new PathFragment("../b"), new PathFragment("a/../../b").normalize()); + assertEquals(new PathFragment(".."), new PathFragment("a/../..").normalize()); + assertEquals(new PathFragment("b"), new PathFragment("a/../b").normalize()); + assertEquals(new PathFragment("a/b"), new PathFragment("a/b/../b").normalize()); + assertEquals(new PathFragment("/.."), new PathFragment("/..").normalize()); + } + + @Test + public void testSerializationSimple() throws Exception { + checkSerialization("a", 91); + } + + @Test + public void testSerializationAbsolute() throws Exception { + checkSerialization("/foo", 94); + } + + @Test + public void testSerializationNested() throws Exception { + checkSerialization("foo/bar/baz", 101); + } + + private void checkSerialization(String pathFragmentString, int expectedSize) throws Exception { + PathFragment a = new PathFragment(pathFragmentString); + byte[] sa = TestUtils.serializeObject(a); + assertEquals(expectedSize, sa.length); + + PathFragment a2 = (PathFragment) TestUtils.deserializeObject(sa); + assertEquals(a, a2); + } +} |