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