View Javadoc
1   /*
2    * Copyright (C) 2017 Magnus Vigerlöf (magnus.vigerlof@gmail.com) and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.treewalk.filter;
11  
12  import static org.junit.Assert.assertEquals;
13  
14  import java.io.IOException;
15  import java.util.ArrayList;
16  import java.util.Arrays;
17  import java.util.Collections;
18  import java.util.List;
19  
20  import org.eclipse.jgit.dircache.DirCache;
21  import org.eclipse.jgit.dircache.DirCacheBuilder;
22  import org.eclipse.jgit.dircache.DirCacheEntry;
23  import org.eclipse.jgit.junit.RepositoryTestCase;
24  import org.eclipse.jgit.lib.FileMode;
25  import org.eclipse.jgit.lib.ObjectId;
26  import org.eclipse.jgit.lib.ObjectInserter;
27  import org.eclipse.jgit.treewalk.TreeWalk;
28  import org.junit.Before;
29  import org.junit.Test;
30  
31  public class PathFilterLogicTest extends RepositoryTestCase {
32  
33  	private ObjectId treeId;
34  
35  	@Before
36  	public void setup() throws IOException {
37  		String[] paths = new String[] {
38  				"a.txt",
39  				"sub1.txt",
40  				"sub1/suba/a.txt",
41  				"sub1/subb/b.txt",
42  				"sub2/suba/a.txt"
43  		};
44  		treeId = createTree(paths);
45  	}
46  
47  	@Test
48  	public void testSinglePath() throws IOException {
49  		List<String> expected = Arrays.asList("sub1/suba/a.txt",
50  				"sub1/subb/b.txt");
51  
52  		TreeFilter tf = PathFilter.create("sub1");
53  		List<String> paths = getMatchingPaths(treeId, tf);
54  
55  		assertEquals(expected, paths);
56  	}
57  
58  	@Test
59  	public void testSingleSubPath() throws IOException {
60  		List<String> expected = Collections.singletonList("sub1/suba/a.txt");
61  
62  		TreeFilter tf = PathFilter.create("sub1/suba");
63  		List<String> paths = getMatchingPaths(treeId, tf);
64  
65  		assertEquals(expected, paths);
66  	}
67  
68  	@Test
69  	public void testSinglePathNegate() throws IOException {
70  		List<String> expected = Arrays.asList("a.txt", "sub1.txt",
71  				"sub2/suba/a.txt");
72  
73  		TreeFilter tf = PathFilter.create("sub1").negate();
74  		List<String> paths = getMatchingPaths(treeId, tf);
75  
76  		assertEquals(expected, paths);
77  	}
78  
79  	@Test
80  	public void testSingleSubPathNegate() throws IOException {
81  		List<String> expected = Arrays.asList("a.txt", "sub1.txt",
82  				"sub1/subb/b.txt", "sub2/suba/a.txt");
83  
84  		TreeFilter tf = PathFilter.create("sub1/suba").negate();
85  		List<String> paths = getMatchingPaths(treeId, tf);
86  
87  		assertEquals(expected, paths);
88  	}
89  
90  	@Test
91  	public void testOrMultiTwoPath() throws IOException {
92  		List<String> expected = Arrays.asList("sub1/suba/a.txt",
93  				"sub1/subb/b.txt", "sub2/suba/a.txt");
94  
95  		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1"),
96  				PathFilter.create("sub2")};
97  		List<String> paths = getMatchingPaths(treeId, OrTreeFilter.create(tf));
98  
99  		assertEquals(expected, paths);
100 	}
101 
102 	@Test
103 	public void testOrMultiThreePath() throws IOException {
104 		List<String> expected = Arrays.asList("sub1.txt", "sub1/suba/a.txt",
105 				"sub1/subb/b.txt", "sub2/suba/a.txt");
106 
107 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1"),
108 				PathFilter.create("sub2"), PathFilter.create("sub1.txt")};
109 		List<String> paths = getMatchingPaths(treeId, OrTreeFilter.create(tf));
110 
111 		assertEquals(expected, paths);
112 	}
113 
114 	@Test
115 	public void testOrMultiTwoSubPath() throws IOException {
116 		List<String> expected = Arrays.asList("sub1/subb/b.txt",
117 				"sub2/suba/a.txt");
118 
119 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1/subb"),
120 				PathFilter.create("sub2/suba")};
121 		List<String> paths = getMatchingPaths(treeId, OrTreeFilter.create(tf));
122 
123 		assertEquals(expected, paths);
124 	}
125 
126 	@Test
127 	public void testOrMultiTwoMixSubPath() throws IOException {
128 		List<String> expected = Arrays.asList("sub1/subb/b.txt",
129 				"sub2/suba/a.txt");
130 
131 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1/subb"),
132 				PathFilter.create("sub2")};
133 		List<String> paths = getMatchingPaths(treeId, OrTreeFilter.create(tf));
134 
135 		assertEquals(expected, paths);
136 	}
137 
138 	@Test
139 	public void testOrMultiTwoMixSubPathNegate() throws IOException {
140 		List<String> expected = Arrays.asList("a.txt", "sub1.txt",
141 				"sub1/suba/a.txt", "sub2/suba/a.txt");
142 
143 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1").negate(),
144 				PathFilter.create("sub1/suba")};
145 		List<String> paths = getMatchingPaths(treeId, OrTreeFilter.create(tf));
146 
147 		assertEquals(expected, paths);
148 	}
149 
150 	@Test
151 	public void testOrMultiThreeMixSubPathNegate() throws IOException {
152 		List<String> expected = Arrays.asList("a.txt", "sub1.txt",
153 				"sub1/suba/a.txt", "sub2/suba/a.txt");
154 
155 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1").negate(),
156 				PathFilter.create("sub1/suba"), PathFilter.create("no/path")};
157 		List<String> paths = getMatchingPaths(treeId, OrTreeFilter.create(tf));
158 
159 		assertEquals(expected, paths);
160 	}
161 
162 	@Test
163 	public void testPatternParentFileMatch() throws IOException {
164 		List<String> expected = Collections.emptyList();
165 
166 		TreeFilter tf = PathFilter.create("a.txt/test/path");
167 		List<String> paths = getMatchingPaths(treeId, tf);
168 
169 		assertEquals(expected, paths);
170 	}
171 
172 	@Test
173 	public void testAndMultiPath() throws IOException {
174 		List<String> expected = Collections.emptyList();
175 
176 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1"),
177 				PathFilter.create("sub2")};
178 		List<String> paths = getMatchingPaths(treeId, AndTreeFilter.create(tf));
179 
180 		assertEquals(expected, paths);
181 	}
182 
183 	@Test
184 	public void testAndMultiPathNegate() throws IOException {
185 		List<String> expected = Arrays.asList("sub1/suba/a.txt",
186 				"sub1/subb/b.txt");
187 
188 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1"),
189 				PathFilter.create("sub2").negate()};
190 		List<String> paths = getMatchingPaths(treeId, AndTreeFilter.create(tf));
191 
192 		assertEquals(expected, paths);
193 	}
194 
195 	@Test
196 	public void testAndMultiSubPathDualNegate() throws IOException {
197 		List<String> expected = Arrays.asList("a.txt", "sub1.txt",
198 				"sub1/subb/b.txt");
199 
200 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1/suba").negate(),
201 				PathFilter.create("sub2").negate()};
202 		List<String> paths = getMatchingPaths(treeId, AndTreeFilter.create(tf));
203 
204 		assertEquals(expected, paths);
205 	}
206 
207 	@Test
208 	public void testAndMultiSubPath() throws IOException {
209 		List<String> expected = Collections.emptyList();
210 
211 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1"),
212 				PathFilter.create("sub2/suba")};
213 		List<String> paths = getMatchingPaths(treeId, AndTreeFilter.create(tf));
214 
215 		assertEquals(expected, paths);
216 	}
217 
218 	@Test
219 	public void testAndMultiSubPathNegate() throws IOException {
220 		List<String> expected = Collections.singletonList("sub1/subb/b.txt");
221 
222 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1"),
223 				PathFilter.create("sub1/suba").negate()};
224 		List<String> paths = getMatchingPaths(treeId, AndTreeFilter.create(tf));
225 
226 		assertEquals(expected, paths);
227 	}
228 
229 	@Test
230 	public void testAndMultiThreeSubPathNegate() throws IOException {
231 		List<String> expected = Collections.singletonList("sub1/subb/b.txt");
232 
233 		TreeFilter[] tf = new TreeFilter[]{PathFilter.create("sub1"),
234 				PathFilter.create("sub1/suba").negate(),
235 				PathFilter.create("no/path").negate()};
236 		List<String> paths = getMatchingPaths(treeId, AndTreeFilter.create(tf));
237 
238 		assertEquals(expected, paths);
239 	}
240 
241 	@Test
242 	public void testTopAndMultiPathDualNegate() throws IOException {
243 		List<String> expected = Arrays.asList("a.txt", "sub1.txt");
244 
245 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1").negate(),
246 				PathFilter.create("sub2").negate()};
247 		List<String> paths = getMatchingPathsFlat(treeId, AndTreeFilter.create(tf));
248 
249 		assertEquals(expected, paths);
250 	}
251 
252 	@Test
253 	public void testTopAndMultiSubPathDualNegate() throws IOException {
254 		List<String> expected = Arrays.asList("a.txt", "sub1.txt", "sub1");
255 
256 		// Filter on 'sub1/suba' is kind of silly for a non-recursive walk.
257 		// The result is interesting though as the 'sub1' path should be
258 		// returned, due to the fact that there may be hits once the pattern
259 		// is tested with one of the leaf paths.
260 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1/suba").negate(),
261 				PathFilter.create("sub2").negate()};
262 		List<String> paths = getMatchingPathsFlat(treeId, AndTreeFilter.create(tf));
263 
264 		assertEquals(expected, paths);
265 	}
266 
267 	@Test
268 	public void testTopOrMultiPathDual() throws IOException {
269 		List<String> expected = Arrays.asList("sub1.txt", "sub2");
270 
271 		TreeFilter[] tf = new TreeFilter[] {PathFilter.create("sub1.txt"),
272 				PathFilter.create("sub2")};
273 		List<String> paths = getMatchingPathsFlat(treeId, OrTreeFilter.create(tf));
274 
275 		assertEquals(expected, paths);
276 	}
277 
278 	@Test
279 	public void testTopNotPath() throws IOException {
280 		List<String> expected = Arrays.asList("a.txt", "sub1.txt", "sub2");
281 
282 		TreeFilter tf = PathFilter.create("sub1");
283 		List<String> paths = getMatchingPathsFlat(treeId, NotTreeFilter.create(tf));
284 
285 		assertEquals(expected, paths);
286 	}
287 
288 	private List<String> getMatchingPaths(final ObjectId objId,
289 			TreeFilter tf) throws IOException {
290 		return getMatchingPaths(objId, tf, true);
291 	}
292 
293 	private List<String> getMatchingPathsFlat(final ObjectId objId,
294 			TreeFilter tf) throws IOException {
295 		return getMatchingPaths(objId, tf, false);
296 	}
297 
298 	private List<String> getMatchingPaths(final ObjectId objId,
299 			TreeFilter tf, boolean recursive) throws IOException {
300 		try (TreeWalk tw = new TreeWalk(db)) {
301 			tw.setFilter(tf);
302 			tw.setRecursive(recursive);
303 			tw.addTree(objId);
304 
305 			List<String> paths = new ArrayList<>();
306 			while (tw.next()) {
307 				paths.add(tw.getPathString());
308 			}
309 			return paths;
310 		}
311 	}
312 
313 	private ObjectId createTree(String... paths) throws IOException {
314 		final ObjectInserter odi = db.newObjectInserter();
315 		final DirCache dc = db.readDirCache();
316 		final DirCacheBuilder builder = dc.builder();
317 		for (String path : paths) {
318 			DirCacheEntry entry = createEntry(path, FileMode.REGULAR_FILE);
319 			builder.add(entry);
320 		}
321 		builder.finish();
322 		final ObjectId objId = dc.writeTree(odi);
323 		odi.flush();
324 		return objId;
325 	}
326 }
327