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 (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 (DirCacheEntry ent : ents) {
98  			b.add(ent);
99  		}
100 		b.finish();
101 
102 		final DirCacheIterator i = new DirCacheIterator(dc);
103 		int pathIdx = 0;
104 		for (; !i.eof(); i.next(1)) {
105 			assertEquals(pathIdx, i.ptr);
106 			assertSame(ents[pathIdx], i.getDirCacheEntry());
107 			pathIdx++;
108 		}
109 		assertEquals(paths.length, pathIdx);
110 	}
111 
112 	@Test
113 	public void testNoSubtree_WithTreeWalk() throws Exception {
114 		final DirCache dc = DirCache.newInCore();
115 
116 		final String[] paths = { "a-", "a0b" };
117 		final FileMode[] modes = { FileMode.EXECUTABLE_FILE, FileMode.GITLINK };
118 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
119 		for (int i = 0; i < paths.length; i++) {
120 			ents[i] = new DirCacheEntry(paths[i]);
121 			ents[i].setFileMode(modes[i]);
122 		}
123 
124 		final DirCacheBuilder b = dc.builder();
125 		for (DirCacheEntry ent : ents) {
126 			b.add(ent);
127 		}
128 		b.finish();
129 
130 		final DirCacheIterator i = new DirCacheIterator(dc);
131 		try (TreeWalk tw = new TreeWalk(db)) {
132 			tw.addTree(i);
133 			int pathIdx = 0;
134 			while (tw.next()) {
135 				assertSame(i, tw.getTree(0, DirCacheIterator.class));
136 				assertEquals(pathIdx, i.ptr);
137 				assertSame(ents[pathIdx], i.getDirCacheEntry());
138 				assertEquals(paths[pathIdx], tw.getPathString());
139 				assertEquals(modes[pathIdx].getBits(), tw.getRawMode(0));
140 				assertSame(modes[pathIdx], tw.getFileMode(0));
141 				pathIdx++;
142 			}
143 			assertEquals(paths.length, pathIdx);
144 		}
145 	}
146 
147 	@Test
148 	public void testSingleSubtree_NoRecursion() throws Exception {
149 		final DirCache dc = DirCache.newInCore();
150 
151 		final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
152 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
153 		for (int i = 0; i < paths.length; i++) {
154 			ents[i] = new DirCacheEntry(paths[i]);
155 			ents[i].setFileMode(FileMode.REGULAR_FILE);
156 		}
157 
158 		final DirCacheBuilder b = dc.builder();
159 		for (DirCacheEntry ent : ents) {
160 			b.add(ent);
161 		}
162 		b.finish();
163 
164 		final String[] expPaths = { "a-", "a", "a0b" };
165 		final FileMode[] expModes = { FileMode.REGULAR_FILE, FileMode.TREE,
166 				FileMode.REGULAR_FILE };
167 		final int expPos[] = { 0, -1, 4 };
168 
169 		final DirCacheIterator i = new DirCacheIterator(dc);
170 		try (TreeWalk tw = new TreeWalk(db)) {
171 			tw.addTree(i);
172 			tw.setRecursive(false);
173 			int pathIdx = 0;
174 			while (tw.next()) {
175 				assertSame(i, tw.getTree(0, DirCacheIterator.class));
176 				assertEquals(expModes[pathIdx].getBits(), tw.getRawMode(0));
177 				assertSame(expModes[pathIdx], tw.getFileMode(0));
178 				assertEquals(expPaths[pathIdx], tw.getPathString());
179 
180 				if (expPos[pathIdx] >= 0) {
181 					assertEquals(expPos[pathIdx], i.ptr);
182 					assertSame(ents[expPos[pathIdx]], i.getDirCacheEntry());
183 				} else {
184 					assertSame(FileMode.TREE, tw.getFileMode(0));
185 				}
186 
187 				pathIdx++;
188 			}
189 			assertEquals(expPaths.length, pathIdx);
190 		}
191 	}
192 
193 	@Test
194 	public void testSingleSubtree_Recursive() throws Exception {
195 		final DirCache dc = DirCache.newInCore();
196 
197 		final FileMode mode = FileMode.REGULAR_FILE;
198 		final String[] paths = { "a-", "a/b", "a/c", "a/d", "a0b" };
199 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
200 		for (int i = 0; i < paths.length; i++) {
201 			ents[i] = new DirCacheEntry(paths[i]);
202 			ents[i].setFileMode(mode);
203 		}
204 
205 		final DirCacheBuilder b = dc.builder();
206 		for (DirCacheEntry ent : ents) {
207 			b.add(ent);
208 		}
209 		b.finish();
210 
211 		final DirCacheIterator i = new DirCacheIterator(dc);
212 		try (TreeWalk tw = new TreeWalk(db)) {
213 			tw.addTree(i);
214 			tw.setRecursive(true);
215 			int pathIdx = 0;
216 			while (tw.next()) {
217 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
218 				assertNotNull(c);
219 				assertEquals(pathIdx, c.ptr);
220 				assertSame(ents[pathIdx], c.getDirCacheEntry());
221 				assertEquals(paths[pathIdx], tw.getPathString());
222 				assertEquals(mode.getBits(), tw.getRawMode(0));
223 				assertSame(mode, tw.getFileMode(0));
224 				pathIdx++;
225 			}
226 			assertEquals(paths.length, pathIdx);
227 		}
228 	}
229 
230 	@Test
231 	public void testTwoLevelSubtree_Recursive() throws Exception {
232 		final DirCache dc = DirCache.newInCore();
233 
234 		final FileMode mode = FileMode.REGULAR_FILE;
235 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
236 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
237 		for (int i = 0; i < paths.length; i++) {
238 			ents[i] = new DirCacheEntry(paths[i]);
239 			ents[i].setFileMode(mode);
240 		}
241 
242 		final DirCacheBuilder b = dc.builder();
243 		for (DirCacheEntry ent : ents) {
244 			b.add(ent);
245 		}
246 		b.finish();
247 
248 		try (TreeWalk tw = new TreeWalk(db)) {
249 			tw.addTree(new DirCacheIterator(dc));
250 			tw.setRecursive(true);
251 			int pathIdx = 0;
252 			while (tw.next()) {
253 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
254 				assertNotNull(c);
255 				assertEquals(pathIdx, c.ptr);
256 				assertSame(ents[pathIdx], c.getDirCacheEntry());
257 				assertEquals(paths[pathIdx], tw.getPathString());
258 				assertEquals(mode.getBits(), tw.getRawMode(0));
259 				assertSame(mode, tw.getFileMode(0));
260 				pathIdx++;
261 			}
262 			assertEquals(paths.length, pathIdx);
263 		}
264 	}
265 
266 	@Test
267 	public void testReset() throws Exception {
268 		final DirCache dc = DirCache.newInCore();
269 
270 		final FileMode mode = FileMode.REGULAR_FILE;
271 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
272 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
273 		for (int i = 0; i < paths.length; i++) {
274 			ents[i] = new DirCacheEntry(paths[i]);
275 			ents[i].setFileMode(mode);
276 		}
277 
278 		final DirCacheBuilder b = dc.builder();
279 		for (DirCacheEntry ent : ents) {
280 			b.add(ent);
281 		}
282 		b.finish();
283 
284 		DirCacheIterator dci = new DirCacheIterator(dc);
285 		assertFalse(dci.eof());
286 		assertEquals("a-", dci.getEntryPathString());
287 		dci.next(1);
288 		assertFalse(dci.eof());
289 		assertEquals("a", dci.getEntryPathString());
290 		dci.next(1);
291 		assertFalse(dci.eof());
292 		assertEquals("a0b", dci.getEntryPathString());
293 		dci.next(1);
294 		assertTrue(dci.eof());
295 
296 		// same entries the second time
297 		dci.reset();
298 		assertFalse(dci.eof());
299 		assertEquals("a-", dci.getEntryPathString());
300 		dci.next(1);
301 		assertFalse(dci.eof());
302 		assertEquals("a", dci.getEntryPathString());
303 		dci.next(1);
304 		assertFalse(dci.eof());
305 		assertEquals("a0b", dci.getEntryPathString());
306 		dci.next(1);
307 		assertTrue(dci.eof());
308 
309 		// Step backwards
310 		dci.back(1);
311 		assertFalse(dci.eof());
312 		assertEquals("a0b", dci.getEntryPathString());
313 		dci.back(1);
314 		assertFalse(dci.eof());
315 		assertEquals("a", dci.getEntryPathString());
316 		dci.back(1);
317 		assertFalse(dci.eof());
318 		assertEquals("a-", dci.getEntryPathString());
319 		assertTrue(dci.first());
320 
321 		// forward
322 		assertFalse(dci.eof());
323 		assertEquals("a-", dci.getEntryPathString());
324 		dci.next(1);
325 		assertFalse(dci.eof());
326 		assertEquals("a", dci.getEntryPathString());
327 		dci.next(1);
328 		assertFalse(dci.eof());
329 		assertEquals("a0b", dci.getEntryPathString());
330 		dci.next(1);
331 		assertTrue(dci.eof());
332 
333 		// backwqrd halways, and forward again
334 		dci.back(1);
335 		assertFalse(dci.eof());
336 		assertEquals("a0b", dci.getEntryPathString());
337 		dci.back(1);
338 		assertFalse(dci.eof());
339 		assertEquals("a", dci.getEntryPathString());
340 
341 		dci.next(1);
342 		assertFalse(dci.eof());
343 		assertEquals("a0b", dci.getEntryPathString());
344 		dci.next(1);
345 		assertTrue(dci.eof());
346 
347 		dci.reset(); // a.
348 		dci.next(1); // a
349 		AbstractTreeIterator sti = dci.createSubtreeIterator(null);
350 		assertEquals("a/b", sti.getEntryPathString());
351 		sti.next(1);
352 		assertEquals("a/c", sti.getEntryPathString());
353 		sti.next(1);
354 		assertEquals("a/d", sti.getEntryPathString());
355 		sti.back(2);
356 		assertEquals("a/b", sti.getEntryPathString());
357 
358 	}
359 
360 	@Test
361 	public void testBackBug396127() throws Exception {
362 		final DirCache dc = DirCache.newInCore();
363 
364 		final FileMode mode = FileMode.REGULAR_FILE;
365 		final String[] paths = { "git-gui/po/fr.po",
366 				"git_remote_helpers/git/repo.py" };
367 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
368 		for (int i = 0; i < paths.length; i++) {
369 			ents[i] = new DirCacheEntry(paths[i]);
370 			ents[i].setFileMode(mode);
371 		}
372 
373 		final DirCacheBuilder b = dc.builder();
374 		for (DirCacheEntry ent : ents) {
375 			b.add(ent);
376 		}
377 		b.finish();
378 
379 		DirCacheIterator dci = new DirCacheIterator(dc);
380 		assertFalse(dci.eof());
381 		assertEquals("git-gui", dci.getEntryPathString());
382 		dci.next(1);
383 		assertFalse(dci.eof());
384 		assertEquals("git_remote_helpers", dci.getEntryPathString());
385 		dci.back(1);
386 		assertFalse(dci.eof());
387 		assertEquals("git-gui", dci.getEntryPathString());
388 		dci.next(1);
389 		assertEquals("git_remote_helpers", dci.getEntryPathString());
390 		dci.next(1);
391 		assertTrue(dci.eof());
392 
393 	}
394 
395 	@Test
396 	public void testTwoLevelSubtree_FilterPath() throws Exception {
397 		final DirCache dc = DirCache.newInCore();
398 
399 		final FileMode mode = FileMode.REGULAR_FILE;
400 		final String[] paths = { "a-", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
401 		final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
402 		for (int i = 0; i < paths.length; i++) {
403 			ents[i] = new DirCacheEntry(paths[i]);
404 			ents[i].setFileMode(mode);
405 		}
406 
407 		final DirCacheBuilder b = dc.builder();
408 		for (DirCacheEntry ent : ents) {
409 			b.add(ent);
410 		}
411 		b.finish();
412 
413 		try (TreeWalk tw = new TreeWalk(db)) {
414 			for (int victimIdx = 0; victimIdx < paths.length; victimIdx++) {
415 				tw.reset();
416 				tw.addTree(new DirCacheIterator(dc));
417 				tw.setFilter(PathFilterGroup.createFromStrings(Collections
418 						.singleton(paths[victimIdx])));
419 				tw.setRecursive(tw.getFilter().shouldBeRecursive());
420 				assertTrue(tw.next());
421 				final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
422 				assertNotNull(c);
423 				assertEquals(victimIdx, c.ptr);
424 				assertSame(ents[victimIdx], c.getDirCacheEntry());
425 				assertEquals(paths[victimIdx], tw.getPathString());
426 				assertEquals(mode.getBits(), tw.getRawMode(0));
427 				assertSame(mode, tw.getFileMode(0));
428 				assertFalse(tw.next());
429 			}
430 		}
431 	}
432 
433 	@Test
434 	public void testRemovedSubtree() throws Exception {
435 		final File path = JGitTestUtil
436 				.getTestResourceFile("dircache.testRemovedSubtree");
437 
438 		final DirCache dc = DirCache.read(path, FS.DETECTED);
439 		assertEquals(2, dc.getEntryCount());
440 
441 		try (TreeWalk tw = new TreeWalk(db)) {
442 			tw.setRecursive(true);
443 			tw.addTree(new DirCacheIterator(dc));
444 
445 			assertTrue(tw.next());
446 			assertEquals("a/a", tw.getPathString());
447 			assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
448 
449 			assertTrue(tw.next());
450 			assertEquals("q", tw.getPathString());
451 			assertSame(FileMode.REGULAR_FILE, tw.getFileMode(0));
452 
453 			assertFalse(tw.next());
454 		}
455 	}
456 }