View Javadoc
1   /*
2    * Copyright (C) 2008-2009, Google Inc. 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  
11  package org.eclipse.jgit.dircache;
12  
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertFalse;
15  import static org.junit.Assert.assertNotNull;
16  import static org.junit.Assert.assertSame;
17  import static org.junit.Assert.assertTrue;
18  
19  import java.io.File;
20  import java.util.Collections;
21  
22  import org.eclipse.jgit.junit.JGitTestUtil;
23  import org.eclipse.jgit.junit.RepositoryTestCase;
24  import org.eclipse.jgit.lib.FileMode;
25  import org.eclipse.jgit.treewalk.AbstractTreeIterator;
26  import org.eclipse.jgit.treewalk.TreeWalk;
27  import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
28  import org.eclipse.jgit.util.FS;
29  import org.junit.Test;
30  
31  public class DirCacheIteratorTest extends RepositoryTestCase {
32  	@Test
33  	public void testEmptyTree_NoTreeWalk() throws Exception {
34  		final DirCache dc = DirCache.newInCore();
35  		assertEquals(0, dc.getEntryCount());
36  
37  		final DirCacheIterator i = new DirCacheIterator(dc);
38  		assertTrue(i.eof());
39  	}
40  
41  	@Test
42  	public void testEmptyTree_WithTreeWalk() throws Exception {
43  		final DirCache dc = DirCache.newInCore();
44  		assertEquals(0, dc.getEntryCount());
45  
46  		try (TreeWalk tw = new TreeWalk(db)) {
47  			tw.addTree(new DirCacheIterator(dc));
48  			assertFalse(tw.next());
49  		}
50  	}
51  
52  	@Test
53  	public void testNoSubtree_NoTreeWalk() throws Exception {
54  		final DirCache dc = DirCache.newInCore();
55  
56  		final String[] paths = { "a-", "a0b" };
57  		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
58  		for (int i = 0; i < paths.length; i++) {
59  			ents[i] = new DirCacheEntry(paths[i]);
60  			ents[i].setFileMode(FileMode.REGULAR_FILE);
61  		}
62  
63  		final DirCacheBuilder b = dc.builder();
64  		for (DirCacheEntry ent : ents) {
65  			b.add(ent);
66  		}
67  		b.finish();
68  
69  		final DirCacheIterator i = new DirCacheIterator(dc);
70  		int pathIdx = 0;
71  		for (; !i.eof(); i.next(1)) {
72  			assertEquals(pathIdx, i.ptr);
73  			assertSame(ents[pathIdx], i.getDirCacheEntry());
74  			pathIdx++;
75  		}
76  		assertEquals(paths.length, pathIdx);
77  	}
78  
79  	@Test
80  	public void testNoSubtree_WithTreeWalk() throws Exception {
81  		final DirCache dc = DirCache.newInCore();
82  
83  		final String[] paths = { "a-", "a0b" };
84  		final FileMode[] modes = { FileMode.EXECUTABLE_FILE, FileMode.GITLINK };
85  		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
86  		for (int i = 0; i < paths.length; i++) {
87  			ents[i] = new DirCacheEntry(paths[i]);
88  			ents[i].setFileMode(modes[i]);
89  		}
90  
91  		final DirCacheBuilder b = dc.builder();
92  		for (DirCacheEntry ent : ents) {
93  			b.add(ent);
94  		}
95  		b.finish();
96  
97  		final DirCacheIterator i = new DirCacheIterator(dc);
98  		try (TreeWalk tw = new TreeWalk(db)) {
99  			tw.addTree(i);
100 			int pathIdx = 0;
101 			while (tw.next()) {
102 				assertSame(i, tw.getTree(0, DirCacheIterator.class));
103 				assertEquals(pathIdx, i.ptr);
104 				assertSame(ents[pathIdx], i.getDirCacheEntry());
105 				assertEquals(paths[pathIdx], tw.getPathString());
106 				assertEquals(modes[pathIdx].getBits(), tw.getRawMode(0));
107 				assertSame(modes[pathIdx], tw.getFileMode(0));
108 				pathIdx++;
109 			}
110 			assertEquals(paths.length, pathIdx);
111 		}
112 	}
113 
114 	@Test
115 	public void testSingleSubtree_NoRecursion() throws Exception {
116 		final DirCache dc = DirCache.newInCore();
117 
118 		final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
119 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
120 		for (int i = 0; i < paths.length; i++) {
121 			ents[i] = new DirCacheEntry(paths[i]);
122 			ents[i].setFileMode(FileMode.REGULAR_FILE);
123 		}
124 
125 		final DirCacheBuilder b = dc.builder();
126 		for (DirCacheEntry ent : ents) {
127 			b.add(ent);
128 		}
129 		b.finish();
130 
131 		final String[] expPaths = { "a-", "a", "a0b" };
132 		final FileMode[] expModes = { FileMode.REGULAR_FILE, FileMode.TREE,
133 				FileMode.REGULAR_FILE };
134 		final int expPos[] = { 0, -1, 4 };
135 
136 		final DirCacheIterator i = new DirCacheIterator(dc);
137 		try (TreeWalk tw = new TreeWalk(db)) {
138 			tw.addTree(i);
139 			tw.setRecursive(false);
140 			int pathIdx = 0;
141 			while (tw.next()) {
142 				assertSame(i, tw.getTree(0, DirCacheIterator.class));
143 				assertEquals(expModes[pathIdx].getBits(), tw.getRawMode(0));
144 				assertSame(expModes[pathIdx], tw.getFileMode(0));
145 				assertEquals(expPaths[pathIdx], tw.getPathString());
146 
147 				if (expPos[pathIdx] >= 0) {
148 					assertEquals(expPos[pathIdx], i.ptr);
149 					assertSame(ents[expPos[pathIdx]], i.getDirCacheEntry());
150 				} else {
151 					assertSame(FileMode.TREE, tw.getFileMode(0));
152 				}
153 
154 				pathIdx++;
155 			}
156 			assertEquals(expPaths.length, pathIdx);
157 		}
158 	}
159 
160 	@Test
161 	public void testSingleSubtree_Recursive() throws Exception {
162 		final DirCache dc = DirCache.newInCore();
163 
164 		final FileMode mode = FileMode.REGULAR_FILE;
165 		final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
166 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
167 		for (int i = 0; i < paths.length; i++) {
168 			ents[i] = new DirCacheEntry(paths[i]);
169 			ents[i].setFileMode(mode);
170 		}
171 
172 		final DirCacheBuilder b = dc.builder();
173 		for (DirCacheEntry ent : ents) {
174 			b.add(ent);
175 		}
176 		b.finish();
177 
178 		final DirCacheIterator i = new DirCacheIterator(dc);
179 		try (TreeWalk tw = new TreeWalk(db)) {
180 			tw.addTree(i);
181 			tw.setRecursive(true);
182 			int pathIdx = 0;
183 			while (tw.next()) {
184 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
185 				assertNotNull(c);
186 				assertEquals(pathIdx, c.ptr);
187 				assertSame(ents[pathIdx], c.getDirCacheEntry());
188 				assertEquals(paths[pathIdx], tw.getPathString());
189 				assertEquals(mode.getBits(), tw.getRawMode(0));
190 				assertSame(mode, tw.getFileMode(0));
191 				pathIdx++;
192 			}
193 			assertEquals(paths.length, pathIdx);
194 		}
195 	}
196 
197 	@Test
198 	public void testTwoLevelSubtree_Recursive() throws Exception {
199 		final DirCache dc = DirCache.newInCore();
200 
201 		final FileMode mode = FileMode.REGULAR_FILE;
202 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
203 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
204 		for (int i = 0; i < paths.length; i++) {
205 			ents[i] = new DirCacheEntry(paths[i]);
206 			ents[i].setFileMode(mode);
207 		}
208 
209 		final DirCacheBuilder b = dc.builder();
210 		for (DirCacheEntry ent : ents) {
211 			b.add(ent);
212 		}
213 		b.finish();
214 
215 		try (TreeWalk tw = new TreeWalk(db)) {
216 			tw.addTree(new DirCacheIterator(dc));
217 			tw.setRecursive(true);
218 			int pathIdx = 0;
219 			while (tw.next()) {
220 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
221 				assertNotNull(c);
222 				assertEquals(pathIdx, c.ptr);
223 				assertSame(ents[pathIdx], c.getDirCacheEntry());
224 				assertEquals(paths[pathIdx], tw.getPathString());
225 				assertEquals(mode.getBits(), tw.getRawMode(0));
226 				assertSame(mode, tw.getFileMode(0));
227 				pathIdx++;
228 			}
229 			assertEquals(paths.length, pathIdx);
230 		}
231 	}
232 
233 	@Test
234 	public void testReset() throws Exception {
235 		final DirCache dc = DirCache.newInCore();
236 
237 		final FileMode mode = FileMode.REGULAR_FILE;
238 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
239 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
240 		for (int i = 0; i < paths.length; i++) {
241 			ents[i] = new DirCacheEntry(paths[i]);
242 			ents[i].setFileMode(mode);
243 		}
244 
245 		final DirCacheBuilder b = dc.builder();
246 		for (DirCacheEntry ent : ents) {
247 			b.add(ent);
248 		}
249 		b.finish();
250 
251 		DirCacheIterator dci = new DirCacheIterator(dc);
252 		assertFalse(dci.eof());
253 		assertEquals("a-", dci.getEntryPathString());
254 		dci.next(1);
255 		assertFalse(dci.eof());
256 		assertEquals("a", dci.getEntryPathString());
257 		dci.next(1);
258 		assertFalse(dci.eof());
259 		assertEquals("a0b", dci.getEntryPathString());
260 		dci.next(1);
261 		assertTrue(dci.eof());
262 
263 		// same entries the second time
264 		dci.reset();
265 		assertFalse(dci.eof());
266 		assertEquals("a-", dci.getEntryPathString());
267 		dci.next(1);
268 		assertFalse(dci.eof());
269 		assertEquals("a", dci.getEntryPathString());
270 		dci.next(1);
271 		assertFalse(dci.eof());
272 		assertEquals("a0b", dci.getEntryPathString());
273 		dci.next(1);
274 		assertTrue(dci.eof());
275 
276 		// Step backwards
277 		dci.back(1);
278 		assertFalse(dci.eof());
279 		assertEquals("a0b", dci.getEntryPathString());
280 		dci.back(1);
281 		assertFalse(dci.eof());
282 		assertEquals("a", dci.getEntryPathString());
283 		dci.back(1);
284 		assertFalse(dci.eof());
285 		assertEquals("a-", dci.getEntryPathString());
286 		assertTrue(dci.first());
287 
288 		// forward
289 		assertFalse(dci.eof());
290 		assertEquals("a-", dci.getEntryPathString());
291 		dci.next(1);
292 		assertFalse(dci.eof());
293 		assertEquals("a", dci.getEntryPathString());
294 		dci.next(1);
295 		assertFalse(dci.eof());
296 		assertEquals("a0b", dci.getEntryPathString());
297 		dci.next(1);
298 		assertTrue(dci.eof());
299 
300 		// backwqrd halways, and forward again
301 		dci.back(1);
302 		assertFalse(dci.eof());
303 		assertEquals("a0b", dci.getEntryPathString());
304 		dci.back(1);
305 		assertFalse(dci.eof());
306 		assertEquals("a", dci.getEntryPathString());
307 
308 		dci.next(1);
309 		assertFalse(dci.eof());
310 		assertEquals("a0b", dci.getEntryPathString());
311 		dci.next(1);
312 		assertTrue(dci.eof());
313 
314 		dci.reset(); // a.
315 		dci.next(1); // a
316 		AbstractTreeIterator sti = dci.createSubtreeIterator(null);
317 		assertEquals("a/b", sti.getEntryPathString());
318 		sti.next(1);
319 		assertEquals("a/c", sti.getEntryPathString());
320 		sti.next(1);
321 		assertEquals("a/d", sti.getEntryPathString());
322 		sti.back(2);
323 		assertEquals("a/b", sti.getEntryPathString());
324 
325 	}
326 
327 	@Test
328 	public void testBackBug396127() throws Exception {
329 		final DirCache dc = DirCache.newInCore();
330 
331 		final FileMode mode = FileMode.REGULAR_FILE;
332 		final String[] paths = { "git-gui/po/fr.po",
333 				"git_remote_helpers/git/repo.py" };
334 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
335 		for (int i = 0; i < paths.length; i++) {
336 			ents[i] = new DirCacheEntry(paths[i]);
337 			ents[i].setFileMode(mode);
338 		}
339 
340 		final DirCacheBuilder b = dc.builder();
341 		for (DirCacheEntry ent : ents) {
342 			b.add(ent);
343 		}
344 		b.finish();
345 
346 		DirCacheIterator dci = new DirCacheIterator(dc);
347 		assertFalse(dci.eof());
348 		assertEquals("git-gui", dci.getEntryPathString());
349 		dci.next(1);
350 		assertFalse(dci.eof());
351 		assertEquals("git_remote_helpers", dci.getEntryPathString());
352 		dci.back(1);
353 		assertFalse(dci.eof());
354 		assertEquals("git-gui", dci.getEntryPathString());
355 		dci.next(1);
356 		assertEquals("git_remote_helpers", dci.getEntryPathString());
357 		dci.next(1);
358 		assertTrue(dci.eof());
359 
360 	}
361 
362 	@Test
363 	public void testTwoLevelSubtree_FilterPath() throws Exception {
364 		final DirCache dc = DirCache.newInCore();
365 
366 		final FileMode mode = FileMode.REGULAR_FILE;
367 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
368 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
369 		for (int i = 0; i < paths.length; i++) {
370 			ents[i] = new DirCacheEntry(paths[i]);
371 			ents[i].setFileMode(mode);
372 		}
373 
374 		final DirCacheBuilder b = dc.builder();
375 		for (DirCacheEntry ent : ents) {
376 			b.add(ent);
377 		}
378 		b.finish();
379 
380 		try (TreeWalk tw = new TreeWalk(db)) {
381 			for (int victimIdx = 0; victimIdx < paths.length; victimIdx++) {
382 				tw.reset();
383 				tw.addTree(new DirCacheIterator(dc));
384 				tw.setFilter(PathFilterGroup.createFromStrings(Collections
385 						.singleton(paths[victimIdx])));
386 				tw.setRecursive(tw.getFilter().shouldBeRecursive());
387 				assertTrue(tw.next());
388 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
389 				assertNotNull(c);
390 				assertEquals(victimIdx, c.ptr);
391 				assertSame(ents[victimIdx], c.getDirCacheEntry());
392 				assertEquals(paths[victimIdx], tw.getPathString());
393 				assertEquals(mode.getBits(), tw.getRawMode(0));
394 				assertSame(mode, tw.getFileMode(0));
395 				assertFalse(tw.next());
396 			}
397 		}
398 	}
399 
400 	@Test
401 	public void testRemovedSubtree() throws Exception {
402 		final File path = JGitTestUtil
403 				.getTestResourceFile("dircache.testRemovedSubtree");
404 
405 		final DirCache dc = DirCache.read(path, FS.DETECTED);
406 		assertEquals(2, dc.getEntryCount());
407 
408 		try (TreeWalk tw = new TreeWalk(db)) {
409 			tw.setRecursive(true);
410 			tw.addTree(new DirCacheIterator(dc));
411 
412 			assertTrue(tw.next());
413 			assertEquals("a/a", tw.getPathString());
414 			assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
415 
416 			assertTrue(tw.next());
417 			assertEquals("q", tw.getPathString());
418 			assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
419 
420 			assertFalse(tw.next());
421 		}
422 	}
423 }