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.treewalk;
45
46 import static java.nio.charset.StandardCharsets.UTF_8;
47 import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
48 import static org.eclipse.jgit.lib.FileMode.SYMLINK;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertSame;
52 import static org.junit.Assert.assertTrue;
53
54 import java.io.ByteArrayOutputStream;
55
56 import org.eclipse.jgit.errors.CorruptObjectException;
57 import org.eclipse.jgit.lib.Constants;
58 import org.eclipse.jgit.lib.FileMode;
59 import org.eclipse.jgit.lib.ObjectId;
60 import org.eclipse.jgit.lib.TreeFormatter;
61 import org.eclipse.jgit.util.RawParseUtils;
62 import org.junit.Before;
63 import org.junit.Test;
64
65 public class CanonicalTreeParserTest {
66 private final CanonicalTreeParser ctp = new CanonicalTreeParser();
67
68 private final FileMode m644 = FileMode.REGULAR_FILE;
69
70 private final FileMode mt = FileMode.TREE;
71
72 private final ObjectId hash_a = ObjectId
73 .fromString("6b9c715d21d5486e59083fb6071566aa6ecd4d42");
74
75 private final ObjectId hash_foo = ObjectId
76 .fromString("a213e8e25bb2442326e86cbfb9ef56319f482869");
77
78 private final ObjectId hash_sometree = ObjectId
79 .fromString("daf4bdb0d7bb24319810fe0e73aa317663448c93");
80
81 private byte[] tree1;
82
83 private byte[] tree2;
84
85 private byte[] tree3;
86
87 @Before
88 public void setUp() throws Exception {
89 tree1 = mktree(entry(m644, "a", hash_a));
90 tree2 = mktree(entry(m644, "a", hash_a), entry(m644, "foo", hash_foo));
91 tree3 = mktree(entry(m644, "a", hash_a), entry(mt, "b_sometree",
92 hash_sometree), entry(m644, "foo", hash_foo));
93 }
94
95 private static byte[] mktree(byte[]... data) throws Exception {
96 final ByteArrayOutputStream out = new ByteArrayOutputStream();
97 for (byte[] e : data)
98 out.write(e);
99 return out.toByteArray();
100 }
101
102 private static byte[] entry(final FileMode mode, final String name,
103 final ObjectId id) throws Exception {
104 final ByteArrayOutputStream out = new ByteArrayOutputStream();
105 mode.copyTo(out);
106 out.write(' ');
107 out.write(Constants.encode(name));
108 out.write(0);
109 id.copyRawTo(out);
110 return out.toByteArray();
111 }
112
113 private String path() {
114 return RawParseUtils.decode(UTF_8, ctp.path,
115 ctp.pathOffset, ctp.pathLen);
116 }
117
118 @Test
119 public void testEmptyTree_AtEOF() throws Exception {
120 ctp.reset(new byte[0]);
121 assertTrue(ctp.eof());
122 }
123
124 @Test
125 public void testOneEntry_Forward() throws Exception {
126 ctp.reset(tree1);
127
128 assertTrue(ctp.first());
129 assertFalse(ctp.eof());
130 assertEquals(m644.getBits(), ctp.mode);
131 assertEquals("a", path());
132 assertEquals(hash_a, ctp.getEntryObjectId());
133
134 ctp.next(1);
135 assertFalse(ctp.first());
136 assertTrue(ctp.eof());
137 }
138
139 @Test
140 public void testTwoEntries_ForwardOneAtATime() throws Exception {
141 ctp.reset(tree2);
142
143 assertTrue(ctp.first());
144 assertFalse(ctp.eof());
145 assertEquals(m644.getBits(), ctp.mode);
146 assertEquals("a", path());
147 assertEquals(hash_a, ctp.getEntryObjectId());
148
149 ctp.next(1);
150 assertFalse(ctp.eof());
151 assertEquals(m644.getBits(), ctp.mode);
152 assertEquals("foo", path());
153 assertEquals(hash_foo, ctp.getEntryObjectId());
154
155 ctp.next(1);
156 assertFalse(ctp.first());
157 assertTrue(ctp.eof());
158 }
159
160 @Test
161 public void testOneEntry_Seek1IsEOF() throws Exception {
162 ctp.reset(tree1);
163 ctp.next(1);
164 assertTrue(ctp.eof());
165 }
166
167 @Test
168 public void testTwoEntries_Seek2IsEOF() throws Exception {
169 ctp.reset(tree2);
170 ctp.next(2);
171 assertTrue(ctp.eof());
172 }
173
174 @Test
175 public void testThreeEntries_Seek3IsEOF() throws Exception {
176 ctp.reset(tree3);
177 ctp.next(3);
178 assertTrue(ctp.eof());
179 }
180
181 @Test
182 public void testThreeEntries_Seek2() throws Exception {
183 ctp.reset(tree3);
184
185 ctp.next(2);
186 assertFalse(ctp.eof());
187 assertFalse(ctp.eof());
188 assertEquals(m644.getBits(), ctp.mode);
189 assertEquals("foo", path());
190 assertEquals(hash_foo, ctp.getEntryObjectId());
191
192 ctp.next(1);
193 assertTrue(ctp.eof());
194 }
195
196 @Test
197 public void testOneEntry_Backwards() throws Exception {
198 ctp.reset(tree1);
199 ctp.next(1);
200 assertFalse(ctp.first());
201 assertTrue(ctp.eof());
202
203 ctp.back(1);
204 assertTrue(ctp.first());
205 assertFalse(ctp.eof());
206 assertEquals(m644.getBits(), ctp.mode);
207 assertEquals("a", path());
208 assertEquals(hash_a, ctp.getEntryObjectId());
209 }
210
211 @Test
212 public void testTwoEntries_BackwardsOneAtATime() throws Exception {
213 ctp.reset(tree2);
214 ctp.next(2);
215 assertTrue(ctp.eof());
216
217 ctp.back(1);
218 assertFalse(ctp.eof());
219 assertEquals(m644.getBits(), ctp.mode);
220 assertEquals("foo", path());
221 assertEquals(hash_foo, ctp.getEntryObjectId());
222
223 ctp.back(1);
224 assertFalse(ctp.eof());
225 assertEquals(m644.getBits(), ctp.mode);
226 assertEquals("a", path());
227 assertEquals(hash_a, ctp.getEntryObjectId());
228 }
229
230 @Test
231 public void testTwoEntries_BackwardsTwo() throws Exception {
232 ctp.reset(tree2);
233 ctp.next(2);
234 assertTrue(ctp.eof());
235
236 ctp.back(2);
237 assertFalse(ctp.eof());
238 assertEquals(m644.getBits(), ctp.mode);
239 assertEquals("a", path());
240 assertEquals(hash_a, ctp.getEntryObjectId());
241
242 ctp.next(1);
243 assertFalse(ctp.eof());
244 assertEquals(m644.getBits(), ctp.mode);
245 assertEquals("foo", path());
246 assertEquals(hash_foo, ctp.getEntryObjectId());
247
248 ctp.next(1);
249 assertTrue(ctp.eof());
250 }
251
252 @Test
253 public void testThreeEntries_BackwardsTwo() throws Exception {
254 ctp.reset(tree3);
255 ctp.next(3);
256 assertTrue(ctp.eof());
257
258 ctp.back(2);
259 assertFalse(ctp.eof());
260 assertEquals(mt.getBits(), ctp.mode);
261 assertEquals("b_sometree", path());
262 assertEquals(hash_sometree, ctp.getEntryObjectId());
263
264 ctp.next(1);
265 assertFalse(ctp.eof());
266 assertEquals(m644.getBits(), ctp.mode);
267 assertEquals("foo", path());
268 assertEquals(hash_foo, ctp.getEntryObjectId());
269
270 ctp.next(1);
271 assertTrue(ctp.eof());
272 }
273
274 @Test
275 public void testBackwards_ConfusingPathName() throws Exception {
276 final String aVeryConfusingName = "confusing 644 entry 755 and others";
277 ctp.reset(mktree(entry(m644, "a", hash_a), entry(mt, aVeryConfusingName,
278 hash_sometree), entry(m644, "foo", hash_foo)));
279 ctp.next(3);
280 assertTrue(ctp.eof());
281
282 ctp.back(2);
283 assertFalse(ctp.eof());
284 assertEquals(mt.getBits(), ctp.mode);
285 assertEquals(aVeryConfusingName, path());
286 assertEquals(hash_sometree, ctp.getEntryObjectId());
287
288 ctp.back(1);
289 assertFalse(ctp.eof());
290 assertEquals(m644.getBits(), ctp.mode);
291 assertEquals("a", path());
292 assertEquals(hash_a, ctp.getEntryObjectId());
293 }
294
295 @Test
296 public void testBackwords_Prebuilts1() throws Exception {
297
298
299
300
301
302 final ObjectId common = ObjectId
303 .fromString("af7bf97cb9bce3f60f1d651a0ef862e9447dd8bc");
304 final ObjectId darwinx86 = ObjectId
305 .fromString("e927f7398240f78face99e1a738dac54ef738e37");
306 final ObjectId linuxx86 = ObjectId
307 .fromString("ac08dd97120c7cb7d06e98cd5b152011183baf21");
308 final ObjectId windows = ObjectId
309 .fromString("6c4c64c221a022bb973165192cca4812033479df");
310
311 ctp.reset(mktree(entry(mt, "common", common), entry(mt, "darwin-x86",
312 darwinx86), entry(mt, "linux-x86", linuxx86), entry(mt,
313 "windows", windows)));
314 ctp.next(3);
315 assertEquals("windows", ctp.getEntryPathString());
316 assertSame(mt, ctp.getEntryFileMode());
317 assertEquals(windows, ctp.getEntryObjectId());
318
319 ctp.back(1);
320 assertEquals("linux-x86", ctp.getEntryPathString());
321 assertSame(mt, ctp.getEntryFileMode());
322 assertEquals(linuxx86, ctp.getEntryObjectId());
323
324 ctp.next(1);
325 assertEquals("windows", ctp.getEntryPathString());
326 assertSame(mt, ctp.getEntryFileMode());
327 assertEquals(windows, ctp.getEntryObjectId());
328 }
329
330 @Test
331 public void testBackwords_Prebuilts2() throws Exception {
332
333
334
335
336
337 final ObjectId common = ObjectId
338 .fromString("af7bf97cb9bce3f60f1d651a0ef862e9447dd8bc");
339 final ObjectId darwinx86 = ObjectId
340 .fromString("0000000000000000000000000000000000000037");
341 final ObjectId linuxx86 = ObjectId
342 .fromString("ac08dd97120c7cb7d06e98cd5b152011183baf21");
343 final ObjectId windows = ObjectId
344 .fromString("6c4c64c221a022bb973165192cca4812033479df");
345
346 ctp.reset(mktree(entry(mt, "common", common), entry(mt, "darwin-x86",
347 darwinx86), entry(mt, "linux-x86", linuxx86), entry(mt,
348 "windows", windows)));
349 ctp.next(3);
350 assertEquals("windows", ctp.getEntryPathString());
351 assertSame(mt, ctp.getEntryFileMode());
352 assertEquals(windows, ctp.getEntryObjectId());
353
354 ctp.back(1);
355 assertEquals("linux-x86", ctp.getEntryPathString());
356 assertSame(mt, ctp.getEntryFileMode());
357 assertEquals(linuxx86, ctp.getEntryObjectId());
358
359 ctp.next(1);
360 assertEquals("windows", ctp.getEntryPathString());
361 assertSame(mt, ctp.getEntryFileMode());
362 assertEquals(windows, ctp.getEntryObjectId());
363 }
364
365 @Test
366 public void testFreakingHugePathName() throws Exception {
367 final int n = AbstractTreeIterator.DEFAULT_PATH_SIZE * 4;
368 final StringBuilder b = new StringBuilder(n);
369 for (int i = 0; i < n; i++)
370 b.append('q');
371 final String name = b.toString();
372 ctp.reset(entry(m644, name, hash_a));
373 assertFalse(ctp.eof());
374 assertEquals(name, RawParseUtils.decode(UTF_8, ctp.path,
375 ctp.pathOffset, ctp.pathLen));
376 }
377
378 @Test
379 public void testFindAttributesWhenFirst() throws CorruptObjectException {
380 TreeFormatter tree = new TreeFormatter();
381 tree.append(".gitattributes", REGULAR_FILE, hash_a);
382 ctp.reset(tree.toByteArray());
383
384 assertTrue(ctp.findFile(".gitattributes"));
385 assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
386 assertEquals(".gitattributes", ctp.getEntryPathString());
387 assertEquals(hash_a, ctp.getEntryObjectId());
388 }
389
390 @Test
391 public void testFindAttributesWhenSecond() throws CorruptObjectException {
392 TreeFormatter tree = new TreeFormatter();
393 tree.append(".config", SYMLINK, hash_a);
394 tree.append(".gitattributes", REGULAR_FILE, hash_foo);
395 ctp.reset(tree.toByteArray());
396
397 assertTrue(ctp.findFile(".gitattributes"));
398 assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
399 assertEquals(".gitattributes", ctp.getEntryPathString());
400 assertEquals(hash_foo, ctp.getEntryObjectId());
401 }
402
403 @Test
404 public void testFindAttributesWhenMissing() throws CorruptObjectException {
405 TreeFormatter tree = new TreeFormatter();
406 tree.append("src", REGULAR_FILE, hash_a);
407 tree.append("zoo", REGULAR_FILE, hash_foo);
408 ctp.reset(tree.toByteArray());
409
410 assertFalse(ctp.findFile(".gitattributes"));
411 assertEquals(11, ctp.idOffset());
412 assertEquals("src", ctp.getEntryPathString());
413 }
414 }