| // 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 com.google.common.truth.Truth.assertThat; |
| import static com.google.devtools.build.lib.testutil.MoreAsserts.assertSameContents; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.fail; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Ordering; |
| import com.google.devtools.build.lib.testutil.MoreAsserts; |
| import com.google.devtools.build.lib.util.BlazeClock; |
| import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * Tests {@link UnixGlob} recursive globs. |
| */ |
| @RunWith(JUnit4.class) |
| public class RecursiveGlobTest { |
| |
| private Path tmpPath; |
| private FileSystem fileSystem; |
| |
| @Before |
| public void setUp() throws Exception { |
| fileSystem = new InMemoryFileSystem(BlazeClock.instance()); |
| tmpPath = fileSystem.getPath("/rglobtmp"); |
| for (String dir : ImmutableList.of("foo/bar/wiz", |
| "foo/baz/wiz", |
| "foo/baz/quip/wiz", |
| "food/baz/wiz", |
| "fool/baz/wiz")) { |
| FileSystemUtils.createDirectoryAndParents(tmpPath.getRelative(dir)); |
| } |
| FileSystemUtils.createEmptyFile(tmpPath.getRelative("foo/bar/wiz/file")); |
| } |
| |
| @Test |
| public void testDoubleStar() throws Exception { |
| assertGlobMatches("**", ".", "foo", "foo/bar", "foo/bar/wiz", "foo/baz", "foo/baz/quip", |
| "foo/baz/quip/wiz", "foo/baz/wiz", "foo/bar/wiz/file", "food", "food/baz", |
| "food/baz/wiz", "fool", "fool/baz", "fool/baz/wiz"); |
| } |
| |
| @Test |
| public void testDoubleDoubleStar() throws Exception { |
| assertGlobMatches("**/**", ".", "foo", "foo/bar", "foo/bar/wiz", "foo/baz", "foo/baz/quip", |
| "foo/baz/quip/wiz", "foo/baz/wiz", "foo/bar/wiz/file", "food", "food/baz", |
| "food/baz/wiz", "fool", "fool/baz", "fool/baz/wiz"); |
| } |
| |
| @Test |
| public void testDirectoryWithDoubleStar() throws Exception { |
| assertGlobMatches("foo/**", "foo", "foo/bar", "foo/bar/wiz", "foo/baz", "foo/baz/quip", |
| "foo/baz/quip/wiz", "foo/baz/wiz", "foo/bar/wiz/file"); |
| } |
| |
| @Test |
| public void testIllegalPatterns() throws Exception { |
| for (String prefix : Lists.newArrayList("", "*/", "**/", "ba/")) { |
| String suffix = ("/" + prefix).substring(0, prefix.length()); |
| for (String pattern : Lists.newArrayList("**fo", "fo**", "**fo**", "fo**fo", "fo**fo**fo")) { |
| assertIllegalWildcard(prefix + pattern); |
| assertIllegalWildcard(pattern + suffix); |
| assertIllegalWildcard("foo", pattern + suffix); |
| } |
| } |
| } |
| |
| @Test |
| public void testDoubleStarPatternWithNamedChild() throws Exception { |
| assertGlobMatches("**/bar", "foo/bar"); |
| } |
| |
| @Test |
| public void testDoubleStarPatternWithChildGlob() throws Exception { |
| assertGlobMatches("**/ba*", |
| "foo/bar", "foo/baz", "food/baz", "fool/baz"); |
| } |
| |
| @Test |
| public void testDoubleStarAsChildGlob() throws Exception { |
| assertGlobMatches("foo/**/wiz", "foo/bar/wiz", "foo/baz/quip/wiz", "foo/baz/wiz"); |
| } |
| |
| @Test |
| public void testDoubleStarUnderNonexistentDirectory() throws Exception { |
| assertGlobMatches("not-there/**" /* => nothing */); |
| } |
| |
| @Test |
| public void testDoubleStarGlobWithNonExistentBase() throws Exception { |
| Collection<Path> globResult = UnixGlob.forPath(fileSystem.getPath("/does/not/exist")) |
| .addPattern("**") |
| .globInterruptible(); |
| assertEquals(0, globResult.size()); |
| } |
| |
| @Test |
| public void testDoubleStarUnderFile() throws Exception { |
| assertGlobMatches("foo/bar/wiz/file/**" /* => nothing */); |
| } |
| |
| @Test |
| public void testSingleFileExclude() throws Exception { |
| assertGlobWithExcludeMatches("**", "food", ".", "foo", "foo/bar", "foo/bar/wiz", "foo/baz", |
| "foo/baz/quip", "foo/baz/quip/wiz", "foo/baz/wiz", |
| "foo/bar/wiz/file", "food/baz", "food/baz/wiz", "fool", "fool/baz", |
| "fool/baz/wiz"); |
| } |
| |
| @Test |
| public void testSingleFileExcludeForDirectoryWithChildGlob() |
| throws Exception { |
| assertGlobWithExcludeMatches("foo/**", "foo", "foo/bar", "foo/bar/wiz", "foo/baz", |
| "foo/baz/quip", "foo/baz/quip/wiz", "foo/baz/wiz", |
| "foo/bar/wiz/file"); |
| } |
| |
| @Test |
| public void testGlobExcludeForDirectoryWithChildGlob() |
| throws Exception { |
| assertGlobWithExcludeMatches("foo/**", "foo/*", "foo", "foo/bar/wiz", "foo/baz/quip", |
| "foo/baz/quip/wiz", "foo/baz/wiz", "foo/bar/wiz/file"); |
| } |
| |
| @Test |
| public void testExcludeAll() throws Exception { |
| assertGlobWithExcludesMatches(Lists.newArrayList("**"), |
| Lists.newArrayList("*", "*/*", "*/*/*", "*/*/*/*"), "."); |
| } |
| |
| @Test |
| public void testManualGlobExcludeForDirectoryWithChildGlob() |
| throws Exception { |
| assertGlobWithExcludesMatches(Lists.newArrayList("foo/**"), |
| Lists.newArrayList("foo", "foo/*", "foo/*/*", "foo/*/*/*")); |
| } |
| |
| private void assertGlobMatches(String pattern, String... expecteds) |
| throws Exception { |
| assertGlobWithExcludesMatches( |
| Collections.singleton(pattern), Collections.<String>emptyList(), |
| expecteds); |
| } |
| |
| private void assertGlobWithExcludeMatches(String pattern, String exclude, |
| String... expecteds) |
| throws Exception { |
| assertGlobWithExcludesMatches( |
| Collections.singleton(pattern), Collections.singleton(exclude), |
| expecteds); |
| } |
| |
| private void assertGlobWithExcludesMatches(Collection<String> pattern, |
| Collection<String> excludes, |
| String... expecteds) throws Exception { |
| assertSameContents(resolvePaths(expecteds), |
| new UnixGlob.Builder(tmpPath) |
| .addPatterns(pattern) |
| .addExcludes(excludes) |
| .globInterruptible()); |
| } |
| |
| private Set<Path> resolvePaths(String... relativePaths) { |
| Set<Path> expectedFiles = new HashSet<>(); |
| for (String expected : relativePaths) { |
| Path file = expected.equals(".") |
| ? tmpPath |
| : tmpPath.getRelative(expected); |
| expectedFiles.add(file); |
| } |
| return expectedFiles; |
| } |
| |
| /** |
| * Tests that a recursive glob returns files in sorted order. |
| */ |
| @Test |
| public void testGlobEntriesAreSorted() throws Exception { |
| List<Path> globResult = new UnixGlob.Builder(tmpPath) |
| .addPattern("**") |
| .setExcludeDirectories(false) |
| .globInterruptible(); |
| |
| assertThat(Ordering.natural().sortedCopy(globResult)).containsExactlyElementsIn(globResult) |
| .inOrder(); |
| } |
| |
| private void assertIllegalWildcard(String pattern, String... excludePatterns) |
| throws Exception { |
| try { |
| new UnixGlob.Builder(tmpPath) |
| .addPattern(pattern) |
| .addExcludes(excludePatterns) |
| .globInterruptible(); |
| fail(); |
| } catch (IllegalArgumentException e) { |
| MoreAsserts.assertContainsRegex("recursive wildcard must be its own segment", e.getMessage()); |
| } |
| } |
| |
| } |