View Javadoc
1   /*
2    * Copyright (C) 2008-2009, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.dircache;
45  
46  import static org.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertFalse;
48  import static org.junit.Assert.assertNotNull;
49  import static org.junit.Assert.assertSame;
50  import static org.junit.Assert.assertTrue;
51  
52  import java.io.File;
53  import java.util.Collections;
54  
55  import org.eclipse.jgit.junit.JGitTestUtil;
56  import org.eclipse.jgit.junit.RepositoryTestCase;
57  import org.eclipse.jgit.lib.FileMode;
58  import org.eclipse.jgit.treewalk.AbstractTreeIterator;
59  import org.eclipse.jgit.treewalk.TreeWalk;
60  import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
61  import org.eclipse.jgit.util.FS;
62  import org.junit.Test;
63  
64  public class DirCacheIteratorTest extends RepositoryTestCase {
65  	@Test
66  	public void testEmptyTree_NoTreeWalk() throws Exception {
67  		final DirCache dc = DirCache.newInCore();
68  		assertEquals(0, dc.getEntryCount());
69  
70  		final DirCacheIterator i = new DirCacheIterator(dc);
71  		assertTrue(i.eof());
72  	}
73  
74  	@Test
75  	public void testEmptyTree_WithTreeWalk() throws Exception {
76  		final DirCache dc = DirCache.newInCore();
77  		assertEquals(0, dc.getEntryCount());
78  
79  		try (final TreeWalk tw = new TreeWalk(db)) {
80  			tw.addTree(new DirCacheIterator(dc));
81  			assertFalse(tw.next());
82  		}
83  	}
84  
85  	@Test
86  	public void testNoSubtree_NoTreeWalk() throws Exception {
87  		final DirCache dc = DirCache.newInCore();
88  
89  		final String[] paths = { "a-", "a0b" };
90  		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
91  		for (int i = 0; i < paths.length; i++) {
92  			ents[i] = new DirCacheEntry(paths[i]);
93  			ents[i].setFileMode(FileMode.REGULAR_FILE);
94  		}
95  
96  		final DirCacheBuilder b = dc.builder();
97  		for (int i = 0; i < ents.length; i++)
98  			b.add(ents[i]);
99  		b.finish();
100 
101 		final DirCacheIterator i = new DirCacheIterator(dc);
102 		int pathIdx = 0;
103 		for (; !i.eof(); i.next(1)) {
104 			assertEquals(pathIdx, i.ptr);
105 			assertSame(ents[pathIdx], i.getDirCacheEntry());
106 			pathIdx++;
107 		}
108 		assertEquals(paths.length, pathIdx);
109 	}
110 
111 	@Test
112 	public void testNoSubtree_WithTreeWalk() throws Exception {
113 		final DirCache dc = DirCache.newInCore();
114 
115 		final String[] paths = { "a-", "a0b" };
116 		final FileMode[] modes = { FileMode.EXECUTABLE_FILE, FileMode.GITLINK };
117 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
118 		for (int i = 0; i < paths.length; i++) {
119 			ents[i] = new DirCacheEntry(paths[i]);
120 			ents[i].setFileMode(modes[i]);
121 		}
122 
123 		final DirCacheBuilder b = dc.builder();
124 		for (int i = 0; i < ents.length; i++)
125 			b.add(ents[i]);
126 		b.finish();
127 
128 		final DirCacheIterator i = new DirCacheIterator(dc);
129 		try (final TreeWalk tw = new TreeWalk(db)) {
130 			tw.addTree(i);
131 			int pathIdx = 0;
132 			while (tw.next()) {
133 				assertSame(i, tw.getTree(0, DirCacheIterator.class));
134 				assertEquals(pathIdx, i.ptr);
135 				assertSame(ents[pathIdx], i.getDirCacheEntry());
136 				assertEquals(paths[pathIdx], tw.getPathString());
137 				assertEquals(modes[pathIdx].getBits(), tw.getRawMode(0));
138 				assertSame(modes[pathIdx], tw.getFileMode(0));
139 				pathIdx++;
140 			}
141 			assertEquals(paths.length, pathIdx);
142 		}
143 	}
144 
145 	@Test
146 	public void testSingleSubtree_NoRecursion() throws Exception {
147 		final DirCache dc = DirCache.newInCore();
148 
149 		final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
150 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
151 		for (int i = 0; i < paths.length; i++) {
152 			ents[i] = new DirCacheEntry(paths[i]);
153 			ents[i].setFileMode(FileMode.REGULAR_FILE);
154 		}
155 
156 		final DirCacheBuilder b = dc.builder();
157 		for (int i = 0; i < ents.length; i++)
158 			b.add(ents[i]);
159 		b.finish();
160 
161 		final String[] expPaths = { "a-", "a", "a0b" };
162 		final FileMode[] expModes = { FileMode.REGULAR_FILE, FileMode.TREE,
163 				FileMode.REGULAR_FILE };
164 		final int expPos[] = { 0, -1, 4 };
165 
166 		final DirCacheIterator i = new DirCacheIterator(dc);
167 		try (final TreeWalk tw = new TreeWalk(db)) {
168 			tw.addTree(i);
169 			tw.setRecursive(false);
170 			int pathIdx = 0;
171 			while (tw.next()) {
172 				assertSame(i, tw.getTree(0, DirCacheIterator.class));
173 				assertEquals(expModes[pathIdx].getBits(), tw.getRawMode(0));
174 				assertSame(expModes[pathIdx], tw.getFileMode(0));
175 				assertEquals(expPaths[pathIdx], tw.getPathString());
176 
177 				if (expPos[pathIdx] >= 0) {
178 					assertEquals(expPos[pathIdx], i.ptr);
179 					assertSame(ents[expPos[pathIdx]], i.getDirCacheEntry());
180 				} else {
181 					assertSame(FileMode.TREE, tw.getFileMode(0));
182 				}
183 
184 				pathIdx++;
185 			}
186 			assertEquals(expPaths.length, pathIdx);
187 		}
188 	}
189 
190 	@Test
191 	public void testSingleSubtree_Recursive() throws Exception {
192 		final DirCache dc = DirCache.newInCore();
193 
194 		final FileMode mode = FileMode.REGULAR_FILE;
195 		final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
196 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
197 		for (int i = 0; i < paths.length; i++) {
198 			ents[i] = new DirCacheEntry(paths[i]);
199 			ents[i].setFileMode(mode);
200 		}
201 
202 		final DirCacheBuilder b = dc.builder();
203 		for (int i = 0; i < ents.length; i++)
204 			b.add(ents[i]);
205 		b.finish();
206 
207 		final DirCacheIterator i = new DirCacheIterator(dc);
208 		try (final TreeWalk tw = new TreeWalk(db)) {
209 			tw.addTree(i);
210 			tw.setRecursive(true);
211 			int pathIdx = 0;
212 			while (tw.next()) {
213 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
214 				assertNotNull(c);
215 				assertEquals(pathIdx, c.ptr);
216 				assertSame(ents[pathIdx], c.getDirCacheEntry());
217 				assertEquals(paths[pathIdx], tw.getPathString());
218 				assertEquals(mode.getBits(), tw.getRawMode(0));
219 				assertSame(mode, tw.getFileMode(0));
220 				pathIdx++;
221 			}
222 			assertEquals(paths.length, pathIdx);
223 		}
224 	}
225 
226 	@Test
227 	public void testTwoLevelSubtree_Recursive() throws Exception {
228 		final DirCache dc = DirCache.newInCore();
229 
230 		final FileMode mode = FileMode.REGULAR_FILE;
231 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
232 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
233 		for (int i = 0; i < paths.length; i++) {
234 			ents[i] = new DirCacheEntry(paths[i]);
235 			ents[i].setFileMode(mode);
236 		}
237 
238 		final DirCacheBuilder b = dc.builder();
239 		for (int i = 0; i < ents.length; i++)
240 			b.add(ents[i]);
241 		b.finish();
242 
243 		try (final TreeWalk tw = new TreeWalk(db)) {
244 			tw.addTree(new DirCacheIterator(dc));
245 			tw.setRecursive(true);
246 			int pathIdx = 0;
247 			while (tw.next()) {
248 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
249 				assertNotNull(c);
250 				assertEquals(pathIdx, c.ptr);
251 				assertSame(ents[pathIdx], c.getDirCacheEntry());
252 				assertEquals(paths[pathIdx], tw.getPathString());
253 				assertEquals(mode.getBits(), tw.getRawMode(0));
254 				assertSame(mode, tw.getFileMode(0));
255 				pathIdx++;
256 			}
257 			assertEquals(paths.length, pathIdx);
258 		}
259 	}
260 
261 	@Test
262 	public void testReset() throws Exception {
263 		final DirCache dc = DirCache.newInCore();
264 
265 		final FileMode mode = FileMode.REGULAR_FILE;
266 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
267 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
268 		for (int i = 0; i < paths.length; i++) {
269 			ents[i] = new DirCacheEntry(paths[i]);
270 			ents[i].setFileMode(mode);
271 		}
272 
273 		final DirCacheBuilder b = dc.builder();
274 		for (int i = 0; i < ents.length; i++)
275 			b.add(ents[i]);
276 		b.finish();
277 
278 		DirCacheIterator dci = new DirCacheIterator(dc);
279 		assertFalse(dci.eof());
280 		assertEquals("a-", dci.getEntryPathString());
281 		dci.next(1);
282 		assertFalse(dci.eof());
283 		assertEquals("a", dci.getEntryPathString());
284 		dci.next(1);
285 		assertFalse(dci.eof());
286 		assertEquals("a0b", dci.getEntryPathString());
287 		dci.next(1);
288 		assertTrue(dci.eof());
289 
290 		// same entries the second time
291 		dci.reset();
292 		assertFalse(dci.eof());
293 		assertEquals("a-", dci.getEntryPathString());
294 		dci.next(1);
295 		assertFalse(dci.eof());
296 		assertEquals("a", dci.getEntryPathString());
297 		dci.next(1);
298 		assertFalse(dci.eof());
299 		assertEquals("a0b", dci.getEntryPathString());
300 		dci.next(1);
301 		assertTrue(dci.eof());
302 
303 		// Step backwards
304 		dci.back(1);
305 		assertFalse(dci.eof());
306 		assertEquals("a0b", dci.getEntryPathString());
307 		dci.back(1);
308 		assertFalse(dci.eof());
309 		assertEquals("a", dci.getEntryPathString());
310 		dci.back(1);
311 		assertFalse(dci.eof());
312 		assertEquals("a-", dci.getEntryPathString());
313 		assertTrue(dci.first());
314 
315 		// forward
316 		assertFalse(dci.eof());
317 		assertEquals("a-", dci.getEntryPathString());
318 		dci.next(1);
319 		assertFalse(dci.eof());
320 		assertEquals("a", dci.getEntryPathString());
321 		dci.next(1);
322 		assertFalse(dci.eof());
323 		assertEquals("a0b", dci.getEntryPathString());
324 		dci.next(1);
325 		assertTrue(dci.eof());
326 
327 		// backwqrd halways, and forward again
328 		dci.back(1);
329 		assertFalse(dci.eof());
330 		assertEquals("a0b", dci.getEntryPathString());
331 		dci.back(1);
332 		assertFalse(dci.eof());
333 		assertEquals("a", dci.getEntryPathString());
334 
335 		dci.next(1);
336 		assertFalse(dci.eof());
337 		assertEquals("a0b", dci.getEntryPathString());
338 		dci.next(1);
339 		assertTrue(dci.eof());
340 
341 		dci.reset(); // a.
342 		dci.next(1); // a
343 		AbstractTreeIterator sti = dci.createSubtreeIterator(null);
344 		assertEquals("a/b", sti.getEntryPathString());
345 		sti.next(1);
346 		assertEquals("a/c", sti.getEntryPathString());
347 		sti.next(1);
348 		assertEquals("a/d", sti.getEntryPathString());
349 		sti.back(2);
350 		assertEquals("a/b", sti.getEntryPathString());
351 
352 	}
353 
354 	@Test
355 	public void testBackBug396127() throws Exception {
356 		final DirCache dc = DirCache.newInCore();
357 
358 		final FileMode mode = FileMode.REGULAR_FILE;
359 		final String[] paths = { "git-gui/po/fr.po",
360 				"git_remote_helpers/git/repo.py" };
361 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
362 		for (int i = 0; i < paths.length; i++) {
363 			ents[i] = new DirCacheEntry(paths[i]);
364 			ents[i].setFileMode(mode);
365 		}
366 
367 		final DirCacheBuilder b = dc.builder();
368 		for (int i = 0; i < ents.length; i++)
369 			b.add(ents[i]);
370 		b.finish();
371 
372 		DirCacheIterator dci = new DirCacheIterator(dc);
373 		assertFalse(dci.eof());
374 		assertEquals("git-gui", dci.getEntryPathString());
375 		dci.next(1);
376 		assertFalse(dci.eof());
377 		assertEquals("git_remote_helpers", dci.getEntryPathString());
378 		dci.back(1);
379 		assertFalse(dci.eof());
380 		assertEquals("git-gui", dci.getEntryPathString());
381 		dci.next(1);
382 		assertEquals("git_remote_helpers", dci.getEntryPathString());
383 		dci.next(1);
384 		assertTrue(dci.eof());
385 
386 	}
387 
388 	@Test
389 	public void testTwoLevelSubtree_FilterPath() throws Exception {
390 		final DirCache dc = DirCache.newInCore();
391 
392 		final FileMode mode = FileMode.REGULAR_FILE;
393 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
394 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
395 		for (int i = 0; i < paths.length; i++) {
396 			ents[i] = new DirCacheEntry(paths[i]);
397 			ents[i].setFileMode(mode);
398 		}
399 
400 		final DirCacheBuilder b = dc.builder();
401 		for (int i = 0; i < ents.length; i++)
402 			b.add(ents[i]);
403 		b.finish();
404 
405 		try (final TreeWalk tw = new TreeWalk(db)) {
406 			for (int victimIdx = 0; victimIdx < paths.length; victimIdx++) {
407 				tw.reset();
408 				tw.addTree(new DirCacheIterator(dc));
409 				tw.setFilter(PathFilterGroup.createFromStrings(Collections
410 						.singleton(paths[victimIdx])));
411 				tw.setRecursive(tw.getFilter().shouldBeRecursive());
412 				assertTrue(tw.next());
413 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
414 				assertNotNull(c);
415 				assertEquals(victimIdx, c.ptr);
416 				assertSame(ents[victimIdx], c.getDirCacheEntry());
417 				assertEquals(paths[victimIdx], tw.getPathString());
418 				assertEquals(mode.getBits(), tw.getRawMode(0));
419 				assertSame(mode, tw.getFileMode(0));
420 				assertFalse(tw.next());
421 			}
422 		}
423 	}
424 
425 	@Test
426 	public void testRemovedSubtree() throws Exception {
427 		final File path = JGitTestUtil
428 				.getTestResourceFile("dircache.testRemovedSubtree");
429 
430 		final DirCache dc = DirCache.read(path, FS.DETECTED);
431 		assertEquals(2, dc.getEntryCount());
432 
433 		try (final TreeWalk tw = new TreeWalk(db)) {
434 			tw.setRecursive(true);
435 			tw.addTree(new DirCacheIterator(dc));
436 
437 			assertTrue(tw.next());
438 			assertEquals("a/a", tw.getPathString());
439 			assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
440 
441 			assertTrue(tw.next());
442 			assertEquals("q", tw.getPathString());
443 			assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
444 
445 			assertFalse(tw.next());
446 		}
447 	}
448 }