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