View Javadoc
1   /*
2    * Copyright (C) 2008-2010, 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.eclipse.jgit.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertArrayEquals;
48  import static org.junit.Assert.assertEquals;
49  import static org.junit.Assert.assertNotNull;
50  import static org.junit.Assert.assertTrue;
51  import static org.junit.Assert.fail;
52  
53  import java.io.BufferedReader;
54  import java.io.ByteArrayOutputStream;
55  import java.io.File;
56  import java.io.FileInputStream;
57  import java.io.InputStreamReader;
58  import java.util.ArrayList;
59  import java.util.Iterator;
60  import java.util.LinkedHashMap;
61  import java.util.Map;
62  
63  import org.eclipse.jgit.errors.CorruptObjectException;
64  import org.eclipse.jgit.junit.JGitTestUtil;
65  import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
66  import org.eclipse.jgit.lib.FileMode;
67  import org.eclipse.jgit.lib.ObjectId;
68  import org.eclipse.jgit.lib.Repository;
69  import org.eclipse.jgit.treewalk.TreeWalk;
70  import org.eclipse.jgit.util.FS;
71  import org.eclipse.jgit.util.IO;
72  import org.junit.Test;
73  
74  public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
75  	private final File index = pathOf("gitgit.index");
76  
77  	@Test
78  	public void testReadIndex_LsFiles() throws Exception {
79  		final Map<String, CGitIndexRecord> ls = readLsFiles();
80  		final DirCache dc = new DirCache(index, FS.DETECTED);
81  		assertEquals(0, dc.getEntryCount());
82  		dc.read();
83  		assertEquals(ls.size(), dc.getEntryCount());
84  		{
85  			final Iterator<CGitIndexRecord> rItr = ls.values().iterator();
86  			for (int i = 0; rItr.hasNext(); i++)
87  				assertEqual(rItr.next(), dc.getEntry(i));
88  		}
89  	}
90  
91  	@Test
92  	public void testTreeWalk_LsFiles() throws Exception {
93  		final Repository db = createBareRepository();
94  		final Map<String, CGitIndexRecord> ls = readLsFiles();
95  		final DirCache dc = new DirCache(index, db.getFS());
96  		assertEquals(0, dc.getEntryCount());
97  		dc.read();
98  		assertEquals(ls.size(), dc.getEntryCount());
99  		{
100 			final Iterator<CGitIndexRecord> rItr = ls.values().iterator();
101 			final TreeWalk tw = new TreeWalk(db);
102 			tw.setRecursive(true);
103 			tw.addTree(new DirCacheIterator(dc));
104 			while (rItr.hasNext()) {
105 				final DirCacheIterator dcItr;
106 
107 				assertTrue(tw.next());
108 				dcItr = tw.getTree(0, DirCacheIterator.class);
109 				assertNotNull(dcItr);
110 
111 				assertEqual(rItr.next(), dcItr.getDirCacheEntry());
112 			}
113 		}
114 	}
115 
116 	@Test
117 	public void testUnsupportedOptionalExtension() throws Exception {
118 		final DirCache dc = new DirCache(pathOf("gitgit.index.ZZZZ"),
119 				FS.DETECTED);
120 		dc.read();
121 		assertEquals(1, dc.getEntryCount());
122 		assertEquals("A", dc.getEntry(0).getPathString());
123 	}
124 
125 	@Test
126 	public void testUnsupportedRequiredExtension() throws Exception {
127 		final DirCache dc = new DirCache(pathOf("gitgit.index.aaaa"),
128 				FS.DETECTED);
129 		try {
130 			dc.read();
131 			fail("Cache loaded an unsupported extension");
132 		} catch (CorruptObjectException err) {
133 			assertEquals("DIRC extension 'aaaa'"
134 					+ " not supported by this version.", err.getMessage());
135 		}
136 	}
137 
138 	@Test
139 	public void testCorruptChecksumAtFooter() throws Exception {
140 		final DirCache dc = new DirCache(pathOf("gitgit.index.badchecksum"),
141 				FS.DETECTED);
142 		try {
143 			dc.read();
144 			fail("Cache loaded despite corrupt checksum");
145 		} catch (CorruptObjectException err) {
146 			assertEquals("DIRC checksum mismatch", err.getMessage());
147 		}
148 	}
149 
150 	private static void assertEqual(final CGitIndexRecord c,
151 			final DirCacheEntry j) {
152 		assertNotNull(c);
153 		assertNotNull(j);
154 
155 		assertEquals(c.path, j.getPathString());
156 		assertEquals(c.id, j.getObjectId());
157 		assertEquals(c.mode, j.getRawMode());
158 		assertEquals(c.stage, j.getStage());
159 	}
160 
161 	@Test
162 	public void testReadIndex_DirCacheTree() throws Exception {
163 		final Map<String, CGitIndexRecord> cList = readLsFiles();
164 		final Map<String, CGitLsTreeRecord> cTree = readLsTree();
165 		final DirCache dc = new DirCache(index, FS.DETECTED);
166 		assertEquals(0, dc.getEntryCount());
167 		dc.read();
168 		assertEquals(cList.size(), dc.getEntryCount());
169 
170 		final DirCacheTree jTree = dc.getCacheTree(false);
171 		assertNotNull(jTree);
172 		assertEquals("", jTree.getNameString());
173 		assertEquals("", jTree.getPathString());
174 		assertTrue(jTree.isValid());
175 		assertEquals(ObjectId
176 				.fromString("698dd0b8d0c299f080559a1cffc7fe029479a408"), jTree
177 				.getObjectId());
178 		assertEquals(cList.size(), jTree.getEntrySpan());
179 
180 		final ArrayList<CGitLsTreeRecord> subtrees = new ArrayList<CGitLsTreeRecord>();
181 		for (final CGitLsTreeRecord r : cTree.values()) {
182 			if (FileMode.TREE.equals(r.mode))
183 				subtrees.add(r);
184 		}
185 		assertEquals(subtrees.size(), jTree.getChildCount());
186 
187 		for (int i = 0; i < jTree.getChildCount(); i++) {
188 			final DirCacheTree sj = jTree.getChild(i);
189 			final CGitLsTreeRecord sc = subtrees.get(i);
190 			assertEquals(sc.path, sj.getNameString());
191 			assertEquals(sc.path + "/", sj.getPathString());
192 			assertTrue(sj.isValid());
193 			assertEquals(sc.id, sj.getObjectId());
194 		}
195 	}
196 
197 	@Test
198 	public void testReadWriteV3() throws Exception {
199 		final File file = pathOf("gitgit.index.v3");
200 		final DirCache dc = new DirCache(file, FS.DETECTED);
201 		dc.read();
202 
203 		assertEquals(10, dc.getEntryCount());
204 		assertV3TreeEntry(0, "dir1/file1.txt", false, false, dc);
205 		assertV3TreeEntry(1, "dir2/file2.txt", true, false, dc);
206 		assertV3TreeEntry(2, "dir3/file3.txt", false, false, dc);
207 		assertV3TreeEntry(3, "dir3/file3a.txt", true, false, dc);
208 		assertV3TreeEntry(4, "dir4/file4.txt", true, false, dc);
209 		assertV3TreeEntry(5, "dir4/file4a.txt", false, false, dc);
210 		assertV3TreeEntry(6, "file.txt", true, false, dc);
211 		assertV3TreeEntry(7, "newdir1/newfile1.txt", false, true, dc);
212 		assertV3TreeEntry(8, "newdir1/newfile2.txt", false, true, dc);
213 		assertV3TreeEntry(9, "newfile.txt", false, true, dc);
214 
215 		final ByteArrayOutputStream bos = new ByteArrayOutputStream();
216 		dc.writeTo(null, bos);
217 		final byte[] indexBytes = bos.toByteArray();
218 		final byte[] expectedBytes = IO.readFully(file);
219 		assertArrayEquals(expectedBytes, indexBytes);
220 	}
221 
222 	private static void assertV3TreeEntry(int indexPosition, String path,
223 			boolean skipWorkTree, boolean intentToAdd, DirCache dc) {
224 		final DirCacheEntry entry = dc.getEntry(indexPosition);
225 		assertEquals(path, entry.getPathString());
226 		assertEquals(skipWorkTree, entry.isSkipWorkTree());
227 		assertEquals(intentToAdd, entry.isIntentToAdd());
228 	}
229 
230 	private static File pathOf(final String name) {
231 		return JGitTestUtil.getTestResourceFile(name);
232 	}
233 
234 	private static Map<String, CGitIndexRecord> readLsFiles() throws Exception {
235 		final LinkedHashMap<String, CGitIndexRecord> r = new LinkedHashMap<String, CGitIndexRecord>();
236 		final BufferedReader br = new BufferedReader(new InputStreamReader(
237 				new FileInputStream(pathOf("gitgit.lsfiles")), "UTF-8"));
238 		try {
239 			String line;
240 			while ((line = br.readLine()) != null) {
241 				final CGitIndexRecord cr = new CGitIndexRecord(line);
242 				r.put(cr.path, cr);
243 			}
244 		} finally {
245 			br.close();
246 		}
247 		return r;
248 	}
249 
250 	private static Map<String, CGitLsTreeRecord> readLsTree() throws Exception {
251 		final LinkedHashMap<String, CGitLsTreeRecord> r = new LinkedHashMap<String, CGitLsTreeRecord>();
252 		final BufferedReader br = new BufferedReader(new InputStreamReader(
253 				new FileInputStream(pathOf("gitgit.lstree")), "UTF-8"));
254 		try {
255 			String line;
256 			while ((line = br.readLine()) != null) {
257 				final CGitLsTreeRecord cr = new CGitLsTreeRecord(line);
258 				r.put(cr.path, cr);
259 			}
260 		} finally {
261 			br.close();
262 		}
263 		return r;
264 	}
265 
266 	private static class CGitIndexRecord {
267 		final int mode;
268 
269 		final ObjectId id;
270 
271 		final int stage;
272 
273 		final String path;
274 
275 		CGitIndexRecord(final String line) {
276 			final int tab = line.indexOf('\t');
277 			final int sp1 = line.indexOf(' ');
278 			final int sp2 = line.indexOf(' ', sp1 + 1);
279 			mode = Integer.parseInt(line.substring(0, sp1), 8);
280 			id = ObjectId.fromString(line.substring(sp1 + 1, sp2));
281 			stage = Integer.parseInt(line.substring(sp2 + 1, tab));
282 			path = line.substring(tab + 1);
283 		}
284 	}
285 
286 	private static class CGitLsTreeRecord {
287 		final int mode;
288 
289 		final ObjectId id;
290 
291 		final String path;
292 
293 		CGitLsTreeRecord(final String line) {
294 			final int tab = line.indexOf('\t');
295 			final int sp1 = line.indexOf(' ');
296 			final int sp2 = line.indexOf(' ', sp1 + 1);
297 			mode = Integer.parseInt(line.substring(0, sp1), 8);
298 			id = ObjectId.fromString(line.substring(sp2 + 1, tab));
299 			path = line.substring(tab + 1);
300 		}
301 	}
302 }