aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/vfs/PathAbstractTest.java
diff options
context:
space:
mode:
authorGravatar tomlu <tomlu@google.com>2018-02-08 15:32:00 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-08 15:34:11 -0800
commita729b9b4c3d7844a7d44934bf3365f92633c0a60 (patch)
tree6329f4baf5b0b83ea6e3bd577b78b8d49afea9f1 /src/test/java/com/google/devtools/build/lib/vfs/PathAbstractTest.java
parent0ab46f0dd95f735056add4dd8a90a76944b81d00 (diff)
Replace path implementation.
Path and PathFragment have been replaced with String-based implementations. They are pretty similar, but each method is dissimilar enough that I did not feel sharing code was appropriate. A summary of changes: PATH ==== * Subsumes LocalPath (deleted, its tests repurposed) * Use a simple string to back Path * Path instances are no longer interned; Reference equality will no longer work * Always normalized (same as before) * Some operations will now be slower, like instance compares (which were previously just a reference check) * Multiple identical paths will now consume more memory since they are not interned PATH FRAGMENT ============= * Use a simple string to back PathFragment * No more segment arrays with interned strings * Always normalized * Remove isNormalized * Replace some isNormalizied uses with containsUpLevelReferences() to check if path fragments try to escape their scope * To check if user input is normalized, supply static methods on PathFragment to validate the string before constructing a PathFragment * Because PathFragments are always normalized, we have to replace checks for literal "." from PathFragment#getPathString to PathFragment#getSafePathString. The latter returns "." for the empty string. * The previous implementation supported efficient segment semantics (segment count, iterating over segments). This is now expensive since we do longer have a segment array. ARTIFACT ======== * Remove Path instance. It is instead dynamically constructed on request. This is necessary to avoid this CL becoming a memory regression. RELNOTES: None PiperOrigin-RevId: 185062932
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/vfs/PathAbstractTest.java')
-rw-r--r--src/test/java/com/google/devtools/build/lib/vfs/PathAbstractTest.java141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/PathAbstractTest.java b/src/test/java/com/google/devtools/build/lib/vfs/PathAbstractTest.java
new file mode 100644
index 0000000000..7494683391
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/vfs/PathAbstractTest.java
@@ -0,0 +1,141 @@
+// Copyright 2017 The Bazel Authors. 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 com.google.common.truth.Truth.assertThat;
+import static java.util.stream.Collectors.toList;
+
+import com.google.common.collect.Lists;
+import com.google.common.testing.EqualsTester;
+import com.google.devtools.build.lib.clock.BlazeClock;
+import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Tests for {@link Path}. */
+public abstract class PathAbstractTest {
+
+ private FileSystem fileSystem;
+ private boolean isCaseSensitive;
+
+ @Before
+ public void setup() {
+ fileSystem = new InMemoryFileSystem(BlazeClock.instance());
+ isCaseSensitive = OsPathPolicy.getFilePathOs().isCaseSensitive();
+ }
+
+ @Test
+ public void testStripsTrailingSlash() {
+ // compare string forms
+ assertThat(create("/foo/bar/").getPathString()).isEqualTo("/foo/bar");
+ // compare fragment forms
+ assertThat(create("/foo/bar/")).isEqualTo(create("/foo/bar"));
+ }
+
+ @Test
+ public void testBasename() throws Exception {
+ assertThat(create("/foo/bar").getBaseName()).isEqualTo("bar");
+ assertThat(create("/foo/").getBaseName()).isEqualTo("foo");
+ assertThat(create("/foo").getBaseName()).isEqualTo("foo");
+ assertThat(create("/").getBaseName()).isEmpty();
+ }
+
+ @Test
+ public void testNormalStringsDoNotAllocate() {
+ String normal1 = "/a/b/hello.txt";
+ assertThat(create(normal1).getPathString()).isSameAs(normal1);
+
+ // Sanity check our testing strategy
+ String notNormal = "/a/../b";
+ assertThat(create(notNormal).getPathString()).isNotSameAs(notNormal);
+ }
+
+ @Test
+ public void testComparableSortOrder() {
+ List<Path> list =
+ Lists.newArrayList(
+ create("/zzz"),
+ create("/ZZZ"),
+ create("/ABC"),
+ create("/aBc"),
+ create("/AbC"),
+ create("/abc"));
+ Collections.sort(list);
+ List<String> result = list.stream().map(Path::getPathString).collect(toList());
+
+ if (isCaseSensitive) {
+ assertThat(result).containsExactly("/ABC", "/AbC", "/ZZZ", "/aBc", "/abc", "/zzz").inOrder();
+ } else {
+ // Partial ordering among case-insensitive items guaranteed by Collections.sort stability
+ assertThat(result).containsExactly("/ABC", "/aBc", "/AbC", "/abc", "/zzz", "/ZZZ").inOrder();
+ }
+ }
+
+ @Test
+ public void testSerialization() throws Exception {
+ FileSystem oldFileSystem = Path.getFileSystemForSerialization();
+ try {
+ Path.setFileSystemForSerialization(fileSystem);
+ Path root = fileSystem.getPath("/");
+ Path p1 = fileSystem.getPath("/foo");
+ Path p2 = fileSystem.getPath("/foo/bar");
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos);
+
+ oos.writeObject(root);
+ oos.writeObject(p1);
+ oos.writeObject(p2);
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bis);
+
+ Path dsRoot = (Path) ois.readObject();
+ Path dsP1 = (Path) ois.readObject();
+ Path dsP2 = (Path) ois.readObject();
+
+ new EqualsTester()
+ .addEqualityGroup(root, dsRoot)
+ .addEqualityGroup(p1, dsP1)
+ .addEqualityGroup(p2, dsP2)
+ .testEquals();
+
+ assertThat(p2.startsWith(p1)).isTrue();
+ assertThat(p2.startsWith(dsP1)).isTrue();
+ assertThat(dsP2.startsWith(p1)).isTrue();
+ assertThat(dsP2.startsWith(dsP1)).isTrue();
+
+ // Regression test for a very specific bug in compareTo involving our incorrect usage of
+ // reference equality rather than logical equality.
+ String relativePathStringA = "child/grandchildA";
+ String relativePathStringB = "child/grandchildB";
+ assertThat(
+ p1.getRelative(relativePathStringA).compareTo(dsP1.getRelative(relativePathStringB)))
+ .isEqualTo(
+ p1.getRelative(relativePathStringA).compareTo(p1.getRelative(relativePathStringB)));
+ } finally {
+ Path.setFileSystemForSerialization(oldFileSystem);
+ }
+ }
+
+ protected Path create(String path) {
+ return Path.create(path, fileSystem);
+ }
+}