1
2
3
4
5
6
7
8
9
10
11
12 package org.eclipse.jgit.lib;
13
14 import static java.lang.Integer.valueOf;
15 import static java.nio.charset.StandardCharsets.UTF_8;
16 import static org.eclipse.jgit.junit.JGitTestUtil.concat;
17 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
18 import static org.eclipse.jgit.lib.Constants.OBJ_BAD;
19 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
20 import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
21 import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
22 import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
23 import static org.eclipse.jgit.lib.Constants.encode;
24 import static org.eclipse.jgit.lib.Constants.encodeASCII;
25 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.DUPLICATE_ENTRIES;
26 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.EMPTY_NAME;
27 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.FULL_PATHNAME;
28 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOT;
29 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTDOT;
30 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTGIT;
31 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.NULL_SHA1;
32 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.TREE_NOT_SORTED;
33 import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE;
34 import static org.eclipse.jgit.util.RawParseUtils.decode;
35 import static org.junit.Assert.assertEquals;
36 import static org.junit.Assert.assertSame;
37 import static org.junit.Assert.assertThrows;
38 import static org.junit.Assert.fail;
39
40 import java.text.MessageFormat;
41
42 import org.eclipse.jgit.errors.CorruptObjectException;
43 import org.eclipse.jgit.internal.JGitText;
44 import org.junit.Before;
45 import org.junit.Test;
46
47 public class ObjectCheckerTest {
48 private static final ObjectChecker SECRET_KEY_CHECKER = new ObjectChecker() {
49 @Override
50 public void checkBlob(byte[] raw) throws CorruptObjectException {
51 String in = decode(raw);
52 if (in.contains("secret_key")) {
53 throw new CorruptObjectException("don't add a secret key");
54 }
55 }
56 };
57
58 private static final ObjectChecker SECRET_KEY_BLOB_CHECKER = new ObjectChecker() {
59 @Override
60 public BlobObjectChecker newBlobObjectChecker() {
61 return new BlobObjectChecker() {
62 private boolean containSecretKey;
63
64 @Override
65 public void update(byte[] in, int offset, int len) {
66 String str = decode(in, offset, offset + len);
67 if (str.contains("secret_key")) {
68 containSecretKey = true;
69 }
70 }
71
72 @Override
73 public void endBlob(AnyObjectId id)
74 throws CorruptObjectException {
75 if (containSecretKey) {
76 throw new CorruptObjectException(
77 "don't add a secret key");
78 }
79 }
80 };
81 }
82 };
83
84 private ObjectChecker checker;
85
86 @Before
87 public void setUp() throws Exception {
88 checker = new ObjectChecker();
89 }
90
91 @Test
92 public void testInvalidType() {
93 String msg = MessageFormat.format(
94 JGitText.get().corruptObjectInvalidType2,
95 valueOf(OBJ_BAD));
96 assertCorrupt(msg, OBJ_BAD, new byte[0]);
97 }
98
99 @Test
100 public void testCheckBlob() throws CorruptObjectException {
101
102 checker.checkBlob(new byte[0]);
103 checker.checkBlob(new byte[1]);
104
105 checker.check(OBJ_BLOB, new byte[0]);
106 checker.check(OBJ_BLOB, new byte[1]);
107 }
108
109 @Test
110 public void testCheckBlobNotCorrupt() throws CorruptObjectException {
111 SECRET_KEY_CHECKER.check(OBJ_BLOB, encodeASCII("key = \"public_key\""));
112 }
113
114 @Test
115 public void testCheckBlobCorrupt() {
116 assertThrows(CorruptObjectException.class, () -> SECRET_KEY_CHECKER
117 .check(OBJ_BLOB, encodeASCII("key = \"secret_key\"")));
118 }
119
120 @Test
121 public void testCheckBlobWithBlobObjectCheckerNotCorrupt()
122 throws CorruptObjectException {
123 SECRET_KEY_BLOB_CHECKER.check(OBJ_BLOB,
124 encodeASCII("key = \"public_key\""));
125 }
126
127 @Test
128 public void testCheckBlobWithBlobObjectCheckerCorrupt() {
129 assertThrows(CorruptObjectException.class, () -> SECRET_KEY_BLOB_CHECKER
130 .check(OBJ_BLOB, encodeASCII("key = \"secret_key\"")));
131 }
132
133 @Test
134 public void testValidCommitNoParent() throws CorruptObjectException {
135 StringBuilder b = new StringBuilder();
136
137 b.append("tree ");
138 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
139 b.append('\n');
140
141 b.append("author A. U. Thor <author@localhost> 1 +0000\n");
142 b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
143
144 byte[] data = encodeASCII(b.toString());
145 checker.checkCommit(data);
146 checker.check(OBJ_COMMIT, data);
147 }
148
149 @Test
150 public void testValidCommitBlankAuthor() throws CorruptObjectException {
151 StringBuilder b = new StringBuilder();
152
153 b.append("tree ");
154 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
155 b.append('\n');
156
157 b.append("author <> 0 +0000\n");
158 b.append("committer <> 0 +0000\n");
159
160 byte[] data = encodeASCII(b.toString());
161 checker.checkCommit(data);
162 checker.check(OBJ_COMMIT, data);
163 }
164
165 @Test
166 public void testCommitCorruptAuthor() throws CorruptObjectException {
167 StringBuilder b = new StringBuilder();
168 b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
169 b.append("author b <b@c> <b@c> 0 +0000\n");
170 b.append("committer <> 0 +0000\n");
171
172 byte[] data = encodeASCII(b.toString());
173 assertCorrupt("bad date", OBJ_COMMIT, data);
174 checker.setAllowInvalidPersonIdent(true);
175 checker.checkCommit(data);
176
177 checker.setAllowInvalidPersonIdent(false);
178 assertSkipListAccepts(OBJ_COMMIT, data);
179 }
180
181 @Test
182 public void testCommitCorruptCommitter() throws CorruptObjectException {
183 StringBuilder b = new StringBuilder();
184 b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
185 b.append("author <> 0 +0000\n");
186 b.append("committer b <b@c> <b@c> 0 +0000\n");
187
188 byte[] data = encodeASCII(b.toString());
189 assertCorrupt("bad date", OBJ_COMMIT, data);
190 checker.setAllowInvalidPersonIdent(true);
191 checker.checkCommit(data);
192
193 checker.setAllowInvalidPersonIdent(false);
194 assertSkipListAccepts(OBJ_COMMIT, data);
195 }
196
197 @Test
198 public void testValidCommit1Parent() throws CorruptObjectException {
199 StringBuilder b = new StringBuilder();
200
201 b.append("tree ");
202 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
203 b.append('\n');
204
205 b.append("parent ");
206 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
207 b.append('\n');
208
209 b.append("author A. U. Thor <author@localhost> 1 +0000\n");
210 b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
211
212 byte[] data = encodeASCII(b.toString());
213 checker.checkCommit(data);
214 checker.check(OBJ_COMMIT, data);
215 }
216
217 @Test
218 public void testValidCommit2Parent() throws CorruptObjectException {
219 StringBuilder b = new StringBuilder();
220
221 b.append("tree ");
222 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
223 b.append('\n');
224
225 b.append("parent ");
226 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
227 b.append('\n');
228
229 b.append("parent ");
230 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
231 b.append('\n');
232
233 b.append("author A. U. Thor <author@localhost> 1 +0000\n");
234 b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
235
236 byte[] data = encodeASCII(b.toString());
237 checker.checkCommit(data);
238 checker.check(OBJ_COMMIT, data);
239 }
240
241 @Test
242 public void testValidCommit128Parent() throws CorruptObjectException {
243 StringBuilder b = new StringBuilder();
244
245 b.append("tree ");
246 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
247 b.append('\n');
248
249 for (int i = 0; i < 128; i++) {
250 b.append("parent ");
251 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
252 b.append('\n');
253 }
254
255 b.append("author A. U. Thor <author@localhost> 1 +0000\n");
256 b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
257
258 byte[] data = encodeASCII(b.toString());
259 checker.checkCommit(data);
260 checker.check(OBJ_COMMIT, data);
261 }
262
263 @Test
264 public void testValidCommitNormalTime() throws CorruptObjectException {
265 StringBuilder b = new StringBuilder();
266 String when = "1222757360 -0730";
267
268 b.append("tree ");
269 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
270 b.append('\n');
271
272 b.append("author A. U. Thor <author@localhost> " + when + "\n");
273 b.append("committer A. U. Thor <author@localhost> " + when + "\n");
274
275 byte[] data = encodeASCII(b.toString());
276 checker.checkCommit(data);
277 checker.check(OBJ_COMMIT, data);
278 }
279
280 @Test
281 public void testInvalidCommitNoTree1() {
282 StringBuilder b = new StringBuilder();
283 b.append("parent ");
284 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
285 b.append('\n');
286 assertCorrupt("no tree header", OBJ_COMMIT, b);
287 }
288
289 @Test
290 public void testInvalidCommitNoTree2() {
291 StringBuilder b = new StringBuilder();
292 b.append("trie ");
293 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
294 b.append('\n');
295 assertCorrupt("no tree header", OBJ_COMMIT, b);
296 }
297
298 @Test
299 public void testInvalidCommitNoTree3() {
300 StringBuilder b = new StringBuilder();
301 b.append("tree");
302 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
303 b.append('\n');
304 assertCorrupt("no tree header", OBJ_COMMIT, b);
305 }
306
307 @Test
308 public void testInvalidCommitNoTree4() {
309 StringBuilder b = new StringBuilder();
310 b.append("tree\t");
311 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
312 b.append('\n');
313 assertCorrupt("no tree header", OBJ_COMMIT, b);
314 }
315
316 @Test
317 public void testInvalidCommitInvalidTree1() {
318 StringBuilder b = new StringBuilder();
319 b.append("tree ");
320 b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
321 b.append('\n');
322 assertCorrupt("invalid tree", OBJ_COMMIT, b);
323 }
324
325 @Test
326 public void testInvalidCommitInvalidTree2() {
327 StringBuilder b = new StringBuilder();
328 b.append("tree ");
329 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
330 b.append("z\n");
331 assertCorrupt("invalid tree", OBJ_COMMIT, b);
332 }
333
334 @Test
335 public void testInvalidCommitInvalidTree3() {
336 StringBuilder b = new StringBuilder();
337 b.append("tree ");
338 b.append("be9b");
339 b.append("\n");
340
341 byte[] data = encodeASCII(b.toString());
342 assertCorrupt("invalid tree", OBJ_COMMIT, data);
343 }
344
345 @Test
346 public void testInvalidCommitInvalidTree4() {
347 StringBuilder b = new StringBuilder();
348 b.append("tree ");
349 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
350 b.append('\n');
351 assertCorrupt("invalid tree", OBJ_COMMIT, b);
352 }
353
354 @Test
355 public void testInvalidCommitInvalidParent1() {
356 StringBuilder b = new StringBuilder();
357 b.append("tree ");
358 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
359 b.append('\n');
360 b.append("parent ");
361 b.append("\n");
362 assertCorrupt("invalid parent", OBJ_COMMIT, b);
363 }
364
365 @Test
366 public void testInvalidCommitInvalidParent2() {
367 StringBuilder b = new StringBuilder();
368 b.append("tree ");
369 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
370 b.append('\n');
371 b.append("parent ");
372 b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
373 b.append("\n");
374 assertCorrupt("invalid parent", OBJ_COMMIT, b);
375 }
376
377 @Test
378 public void testInvalidCommitInvalidParent3() {
379 StringBuilder b = new StringBuilder();
380 b.append("tree ");
381 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
382 b.append('\n');
383 b.append("parent ");
384 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
385 b.append("\n");
386 assertCorrupt("invalid parent", OBJ_COMMIT, b);
387 }
388
389 @Test
390 public void testInvalidCommitInvalidParent4() {
391 StringBuilder b = new StringBuilder();
392 b.append("tree ");
393 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
394 b.append('\n');
395 b.append("parent ");
396 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
397 b.append("z\n");
398 assertCorrupt("invalid parent", OBJ_COMMIT, b);
399 }
400
401 @Test
402 public void testInvalidCommitInvalidParent5() {
403 StringBuilder b = new StringBuilder();
404 b.append("tree ");
405 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
406 b.append('\n');
407 b.append("parent\t");
408 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
409 b.append("\n");
410
411 byte[] data = encodeASCII(b.toString());
412
413
414 assertCorrupt("no author", OBJ_COMMIT, data);
415 }
416
417 @Test
418 public void testInvalidCommitNoAuthor() throws CorruptObjectException {
419 StringBuilder b = new StringBuilder();
420 b.append("tree ");
421 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
422 b.append('\n');
423 b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
424
425 byte[] data = encodeASCII(b.toString());
426 assertCorrupt("no author", OBJ_COMMIT, data);
427 assertSkipListAccepts(OBJ_COMMIT, data);
428 }
429
430 @Test
431 public void testInvalidCommitNoCommitter1() throws CorruptObjectException {
432 StringBuilder b = new StringBuilder();
433 b.append("tree ");
434 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
435 b.append('\n');
436 b.append("author A. U. Thor <author@localhost> 1 +0000\n");
437
438 byte[] data = encodeASCII(b.toString());
439 assertCorrupt("no committer", OBJ_COMMIT, data);
440 assertSkipListAccepts(OBJ_COMMIT, data);
441 }
442
443 @Test
444 public void testInvalidCommitNoCommitter2() throws CorruptObjectException {
445 StringBuilder b = new StringBuilder();
446 b.append("tree ");
447 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
448 b.append('\n');
449 b.append("author A. U. Thor <author@localhost> 1 +0000\n");
450 b.append("\n");
451
452 byte[] data = encodeASCII(b.toString());
453 assertCorrupt("no committer", OBJ_COMMIT, data);
454 assertSkipListAccepts(OBJ_COMMIT, data);
455 }
456
457 @Test
458 public void testInvalidCommitInvalidAuthor1()
459 throws CorruptObjectException {
460 StringBuilder b = new StringBuilder();
461 b.append("tree ");
462 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
463 b.append('\n');
464 b.append("author A. U. Thor <foo 1 +0000\n");
465
466 byte[] data = encodeASCII(b.toString());
467 assertCorrupt("bad email", OBJ_COMMIT, data);
468 assertSkipListAccepts(OBJ_COMMIT, data);
469 }
470
471 @Test
472 public void testInvalidCommitInvalidAuthor2()
473 throws CorruptObjectException {
474 StringBuilder b = new StringBuilder();
475 b.append("tree ");
476 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
477 b.append('\n');
478 b.append("author A. U. Thor foo> 1 +0000\n");
479
480 byte[] data = encodeASCII(b.toString());
481 assertCorrupt("missing email", OBJ_COMMIT, data);
482 assertSkipListAccepts(OBJ_COMMIT, data);
483 }
484
485 @Test
486 public void testInvalidCommitInvalidAuthor3()
487 throws CorruptObjectException {
488 StringBuilder b = new StringBuilder();
489 b.append("tree ");
490 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
491 b.append('\n');
492 b.append("author 1 +0000\n");
493
494 byte[] data = encodeASCII(b.toString());
495 assertCorrupt("missing email", OBJ_COMMIT, data);
496 assertSkipListAccepts(OBJ_COMMIT, data);
497 }
498
499 @Test
500 public void testInvalidCommitInvalidAuthor4()
501 throws CorruptObjectException {
502 StringBuilder b = new StringBuilder();
503 b.append("tree ");
504 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
505 b.append('\n');
506 b.append("author a <b> +0000\n");
507
508 byte[] data = encodeASCII(b.toString());
509 assertCorrupt("bad date", OBJ_COMMIT, data);
510 assertSkipListAccepts(OBJ_COMMIT, data);
511 }
512
513 @Test
514 public void testInvalidCommitInvalidAuthor5()
515 throws CorruptObjectException {
516 StringBuilder b = new StringBuilder();
517 b.append("tree ");
518 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
519 b.append('\n');
520 b.append("author a <b>\n");
521
522 byte[] data = encodeASCII(b.toString());
523 assertCorrupt("bad date", OBJ_COMMIT, data);
524 assertSkipListAccepts(OBJ_COMMIT, data);
525 }
526
527 @Test
528 public void testInvalidCommitInvalidAuthor6()
529 throws CorruptObjectException {
530 StringBuilder b = new StringBuilder();
531 b.append("tree ");
532 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
533 b.append('\n');
534 b.append("author a <b> z");
535
536 byte[] data = encodeASCII(b.toString());
537 assertCorrupt("bad date", OBJ_COMMIT, data);
538 assertSkipListAccepts(OBJ_COMMIT, data);
539 }
540
541 @Test
542 public void testInvalidCommitInvalidAuthor7()
543 throws CorruptObjectException {
544 StringBuilder b = new StringBuilder();
545 b.append("tree ");
546 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
547 b.append('\n');
548 b.append("author a <b> 1 z");
549
550 byte[] data = encodeASCII(b.toString());
551 assertCorrupt("bad time zone", OBJ_COMMIT, data);
552 assertSkipListAccepts(OBJ_COMMIT, data);
553 }
554
555 @Test
556 public void testInvalidCommitInvalidCommitter()
557 throws CorruptObjectException {
558 StringBuilder b = new StringBuilder();
559 b.append("tree ");
560 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
561 b.append('\n');
562 b.append("author a <b> 1 +0000\n");
563 b.append("committer a <");
564
565 byte[] data = encodeASCII(b.toString());
566 assertCorrupt("bad email", OBJ_COMMIT, data);
567 assertSkipListAccepts(OBJ_COMMIT, data);
568 }
569
570 @Test
571 public void testValidTag() throws CorruptObjectException {
572 StringBuilder b = new StringBuilder();
573 b.append("object ");
574 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
575 b.append('\n');
576 b.append("type commit\n");
577 b.append("tag test-tag\n");
578 b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
579
580 byte[] data = encodeASCII(b.toString());
581 checker.checkTag(data);
582 checker.check(OBJ_TAG, data);
583 }
584
585 @Test
586 public void testInvalidTagNoObject1() {
587 assertCorrupt("no object header", OBJ_TAG, new byte[0]);
588 }
589
590 @Test
591 public void testInvalidTagNoObject2() {
592 StringBuilder b = new StringBuilder();
593 b.append("object\t");
594 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
595 b.append('\n');
596 assertCorrupt("no object header", OBJ_TAG, b);
597 }
598
599 @Test
600 public void testInvalidTagNoObject3() {
601 StringBuilder b = new StringBuilder();
602 b.append("obejct ");
603 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
604 b.append('\n');
605 assertCorrupt("no object header", OBJ_TAG, b);
606 }
607
608 @Test
609 public void testInvalidTagNoObject4() {
610 StringBuilder b = new StringBuilder();
611 b.append("object ");
612 b.append("zz9bfa841874ccc9f2ef7c48d0c76226f89b7189");
613 b.append('\n');
614 assertCorrupt("invalid object", OBJ_TAG, b);
615 }
616
617 @Test
618 public void testInvalidTagNoObject5() {
619 StringBuilder b = new StringBuilder();
620 b.append("object ");
621 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
622 b.append(" \n");
623 assertCorrupt("invalid object", OBJ_TAG, b);
624 }
625
626 @Test
627 public void testInvalidTagNoObject6() {
628 StringBuilder b = new StringBuilder();
629 b.append("object ");
630 b.append("be9");
631 assertCorrupt("invalid object", OBJ_TAG, b);
632 }
633
634 @Test
635 public void testInvalidTagNoType1() {
636 StringBuilder b = new StringBuilder();
637 b.append("object ");
638 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
639 b.append('\n');
640 assertCorrupt("no type header", OBJ_TAG, b);
641 }
642
643 @Test
644 public void testInvalidTagNoType2() {
645 StringBuilder b = new StringBuilder();
646 b.append("object ");
647 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
648 b.append('\n');
649 b.append("type\tcommit\n");
650 assertCorrupt("no type header", OBJ_TAG, b);
651 }
652
653 @Test
654 public void testInvalidTagNoType3() {
655 StringBuilder b = new StringBuilder();
656 b.append("object ");
657 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
658 b.append('\n');
659 b.append("tpye commit\n");
660 assertCorrupt("no type header", OBJ_TAG, b);
661 }
662
663 @Test
664 public void testInvalidTagNoType4() {
665 StringBuilder b = new StringBuilder();
666 b.append("object ");
667 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
668 b.append('\n');
669 b.append("type commit");
670 assertCorrupt("no tag header", OBJ_TAG, b);
671 }
672
673 @Test
674 public void testInvalidTagNoTagHeader1() {
675 StringBuilder b = new StringBuilder();
676 b.append("object ");
677 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
678 b.append('\n');
679 b.append("type commit\n");
680 assertCorrupt("no tag header", OBJ_TAG, b);
681 }
682
683 @Test
684 public void testInvalidTagNoTagHeader2() {
685 StringBuilder b = new StringBuilder();
686 b.append("object ");
687 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
688 b.append('\n');
689 b.append("type commit\n");
690 b.append("tag\tfoo\n");
691 assertCorrupt("no tag header", OBJ_TAG, b);
692 }
693
694 @Test
695 public void testInvalidTagNoTagHeader3() {
696 StringBuilder b = new StringBuilder();
697 b.append("object ");
698 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
699 b.append('\n');
700 b.append("type commit\n");
701 b.append("tga foo\n");
702 assertCorrupt("no tag header", OBJ_TAG, b);
703 }
704
705 @Test
706 public void testValidTagHasNoTaggerHeader() throws CorruptObjectException {
707 StringBuilder b = new StringBuilder();
708 b.append("object ");
709 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
710 b.append('\n');
711 b.append("type commit\n");
712 b.append("tag foo\n");
713 checker.checkTag(encodeASCII(b.toString()));
714 }
715
716 @Test
717 public void testInvalidTagInvalidTaggerHeader1()
718 throws CorruptObjectException {
719 StringBuilder b = new StringBuilder();
720 b.append("object ");
721 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
722 b.append('\n');
723 b.append("type commit\n");
724 b.append("tag foo\n");
725 b.append("tagger \n");
726
727 byte[] data = encodeASCII(b.toString());
728 assertCorrupt("missing email", OBJ_TAG, data);
729 checker.setAllowInvalidPersonIdent(true);
730 checker.checkTag(data);
731
732 checker.setAllowInvalidPersonIdent(false);
733 assertSkipListAccepts(OBJ_TAG, data);
734 }
735
736 @Test
737 public void testInvalidTagInvalidTaggerHeader3()
738 throws CorruptObjectException {
739 StringBuilder b = new StringBuilder();
740 b.append("object ");
741 b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
742 b.append('\n');
743 b.append("type commit\n");
744 b.append("tag foo\n");
745 b.append("tagger a < 1 +000\n");
746
747 byte[] data = encodeASCII(b.toString());
748 assertCorrupt("bad email", OBJ_TAG, data);
749 assertSkipListAccepts(OBJ_TAG, data);
750 }
751
752 @Test
753 public void testValidEmptyTree() throws CorruptObjectException {
754 checker.checkTree(new byte[0]);
755 checker.check(OBJ_TREE, new byte[0]);
756 }
757
758 @Test
759 public void testValidTree1() throws CorruptObjectException {
760 StringBuilder b = new StringBuilder();
761 entry(b, "100644 regular-file");
762 checker.checkTree(encodeASCII(b.toString()));
763 }
764
765 @Test
766 public void testValidTree2() throws CorruptObjectException {
767 StringBuilder b = new StringBuilder();
768 entry(b, "100755 executable");
769 checker.checkTree(encodeASCII(b.toString()));
770 }
771
772 @Test
773 public void testValidTree3() throws CorruptObjectException {
774 StringBuilder b = new StringBuilder();
775 entry(b, "40000 tree");
776 checker.checkTree(encodeASCII(b.toString()));
777 }
778
779 @Test
780 public void testValidTree4() throws CorruptObjectException {
781 StringBuilder b = new StringBuilder();
782 entry(b, "120000 symlink");
783 checker.checkTree(encodeASCII(b.toString()));
784 }
785
786 @Test
787 public void testValidTree5() throws CorruptObjectException {
788 StringBuilder b = new StringBuilder();
789 entry(b, "160000 git link");
790 checker.checkTree(encodeASCII(b.toString()));
791 }
792
793 @Test
794 public void testValidTree6() throws CorruptObjectException {
795 StringBuilder b = new StringBuilder();
796 entry(b, "100644 .a");
797 checker.checkTree(encodeASCII(b.toString()));
798 }
799
800 @Test
801 public void testValidTreeWithGitmodules() throws CorruptObjectException {
802 ObjectId treeId = ObjectId
803 .fromString("0123012301230123012301230123012301230123");
804 StringBuilder b = new StringBuilder();
805 ObjectId blobId = entry(b, "100644 .gitmodules");
806
807 byte[] data = encodeASCII(b.toString());
808 checker.checkTree(treeId, data);
809 assertEquals(1, checker.getGitsubmodules().size());
810 assertEquals(treeId, checker.getGitsubmodules().get(0).getTreeId());
811 assertEquals(blobId, checker.getGitsubmodules().get(0).getBlobId());
812 }
813
814
815
816
817
818
819
820
821 @Test
822 public void testNTFSGitmodules() throws CorruptObjectException {
823 for (String gitmodules : new String[] {
824 ".GITMODULES",
825 ".gitmodules",
826 ".Gitmodules",
827 ".gitmoduleS",
828 "gitmod~1",
829 "GITMOD~1",
830 "gitmod~4",
831 "GI7EBA~1",
832 "gi7eba~9",
833 "GI7EB~10",
834 "GI7E~123",
835 "~1000000",
836 "~9999999"
837 }) {
838 checker = new ObjectChecker();
839 checker.setSafeForWindows(true);
840 ObjectId treeId = ObjectId
841 .fromString("0123012301230123012301230123012301230123");
842 StringBuilder b = new StringBuilder();
843 ObjectId blobId = entry(b, "100644 " + gitmodules);
844
845 byte[] data = encodeASCII(b.toString());
846 checker.checkTree(treeId, data);
847 assertEquals(1, checker.getGitsubmodules().size());
848 assertEquals(treeId, checker.getGitsubmodules().get(0).getTreeId());
849 assertEquals(blobId, checker.getGitsubmodules().get(0).getBlobId());
850 }
851 }
852
853 @Test
854 public void testNotGitmodules() throws CorruptObjectException {
855 for (String notGitmodules : new String[] {
856 ".gitmodu",
857 ".gitmodules oh never mind",
858 }) {
859 checker = new ObjectChecker();
860 checker.setSafeForWindows(true);
861 ObjectId treeId = ObjectId
862 .fromString("0123012301230123012301230123012301230123");
863 StringBuilder b = new StringBuilder();
864 entry(b, "100644 " + notGitmodules);
865
866 byte[] data = encodeASCII(b.toString());
867 checker.checkTree(treeId, data);
868 assertEquals(0, checker.getGitsubmodules().size());
869 }
870 }
871
872
873
874
875
876
877 @Test
878 public void testValidTreeWithGitmodulesUppercase()
879 throws CorruptObjectException {
880 ObjectId treeId = ObjectId
881 .fromString("0123012301230123012301230123012301230123");
882 StringBuilder b = new StringBuilder();
883 ObjectId blobId = entry(b, "100644 .GITMODULES");
884
885 byte[] data = encodeASCII(b.toString());
886 checker.setSafeForWindows(true);
887 checker.checkTree(treeId, data);
888 assertEquals(1, checker.getGitsubmodules().size());
889 assertEquals(treeId, checker.getGitsubmodules().get(0).getTreeId());
890 assertEquals(blobId, checker.getGitsubmodules().get(0).getBlobId());
891 }
892
893 @Test
894 public void testTreeWithInvalidGitmodules() throws CorruptObjectException {
895 ObjectId treeId = ObjectId
896 .fromString("0123012301230123012301230123012301230123");
897 StringBuilder b = new StringBuilder();
898 entry(b, "100644 .gitmodulez");
899
900 byte[] data = encodeASCII(b.toString());
901 checker.checkTree(treeId, data);
902 checker.setSafeForWindows(true);
903 assertEquals(0, checker.getGitsubmodules().size());
904 }
905
906 @Test
907 public void testNullSha1InTreeEntry() throws CorruptObjectException {
908 byte[] data = concat(
909 encodeASCII("100644 A"), new byte[] { '\0' },
910 new byte[OBJECT_ID_LENGTH]);
911 assertCorrupt("entry points to null SHA-1", OBJ_TREE, data);
912 assertSkipListAccepts(OBJ_TREE, data);
913 checker.setIgnore(NULL_SHA1, true);
914 checker.checkTree(data);
915 }
916
917 @Test
918 public void testValidPosixTree() throws CorruptObjectException {
919 checkOneName("a<b>c:d|e");
920 checkOneName("test ");
921 checkOneName("test.");
922 checkOneName("NUL");
923 }
924
925 @Test
926 public void testValidTreeSorting1() throws CorruptObjectException {
927 StringBuilder b = new StringBuilder();
928 entry(b, "100644 fooaaa");
929 entry(b, "100755 foobar");
930 checker.checkTree(encodeASCII(b.toString()));
931 }
932
933 @Test
934 public void testValidTreeSorting2() throws CorruptObjectException {
935 StringBuilder b = new StringBuilder();
936 entry(b, "100755 fooaaa");
937 entry(b, "100644 foobar");
938 checker.checkTree(encodeASCII(b.toString()));
939 }
940
941 @Test
942 public void testValidTreeSorting3() throws CorruptObjectException {
943 StringBuilder b = new StringBuilder();
944 entry(b, "40000 a");
945 entry(b, "100644 b");
946 checker.checkTree(encodeASCII(b.toString()));
947 }
948
949 @Test
950 public void testValidTreeSorting4() throws CorruptObjectException {
951 StringBuilder b = new StringBuilder();
952 entry(b, "100644 a");
953 entry(b, "40000 b");
954 checker.checkTree(encodeASCII(b.toString()));
955 }
956
957 @Test
958 public void testValidTreeSorting5() throws CorruptObjectException {
959 StringBuilder b = new StringBuilder();
960 entry(b, "100644 a.c");
961 entry(b, "40000 a");
962 entry(b, "100644 a0c");
963 checker.checkTree(encodeASCII(b.toString()));
964 }
965
966 @Test
967 public void testValidTreeSorting6() throws CorruptObjectException {
968 StringBuilder b = new StringBuilder();
969 entry(b, "40000 a");
970 entry(b, "100644 apple");
971 checker.checkTree(encodeASCII(b.toString()));
972 }
973
974 @Test
975 public void testValidTreeSorting7() throws CorruptObjectException {
976 StringBuilder b = new StringBuilder();
977 entry(b, "40000 an orang");
978 entry(b, "40000 an orange");
979 checker.checkTree(encodeASCII(b.toString()));
980 }
981
982 @Test
983 public void testValidTreeSorting8() throws CorruptObjectException {
984 StringBuilder b = new StringBuilder();
985 entry(b, "100644 a");
986 entry(b, "100644 a0c");
987 entry(b, "100644 b");
988 checker.checkTree(encodeASCII(b.toString()));
989 }
990
991 @Test
992 public void testAcceptTreeModeWithZero() throws CorruptObjectException {
993 StringBuilder b = new StringBuilder();
994 entry(b, "040000 a");
995 byte[] data = encodeASCII(b.toString());
996 checker.setAllowLeadingZeroFileMode(true);
997 checker.checkTree(data);
998
999 checker.setAllowLeadingZeroFileMode(false);
1000 assertSkipListAccepts(OBJ_TREE, data);
1001
1002 checker.setIgnore(ZERO_PADDED_FILEMODE, true);
1003 checker.checkTree(data);
1004 }
1005
1006 @Test
1007 public void testInvalidTreeModeStartsWithZero1() {
1008 StringBuilder b = new StringBuilder();
1009 entry(b, "0 a");
1010 assertCorrupt("mode starts with '0'", OBJ_TREE, b);
1011 }
1012
1013 @Test
1014 public void testInvalidTreeModeStartsWithZero2() {
1015 StringBuilder b = new StringBuilder();
1016 entry(b, "0100644 a");
1017 assertCorrupt("mode starts with '0'", OBJ_TREE, b);
1018 }
1019
1020 @Test
1021 public void testInvalidTreeModeStartsWithZero3() {
1022 StringBuilder b = new StringBuilder();
1023 entry(b, "040000 a");
1024 assertCorrupt("mode starts with '0'", OBJ_TREE, b);
1025 }
1026
1027 @Test
1028 public void testInvalidTreeModeNotOctal1() {
1029 StringBuilder b = new StringBuilder();
1030 entry(b, "8 a");
1031 assertCorrupt("invalid mode character", OBJ_TREE, b);
1032 }
1033
1034 @Test
1035 public void testInvalidTreeModeNotOctal2() {
1036 StringBuilder b = new StringBuilder();
1037 entry(b, "Z a");
1038 byte[] data = encodeASCII(b.toString());
1039 assertCorrupt("invalid mode character", OBJ_TREE, data);
1040 assertSkipListRejects("invalid mode character", OBJ_TREE, data);
1041 }
1042
1043 @Test
1044 public void testInvalidTreeModeNotSupportedMode1() {
1045 StringBuilder b = new StringBuilder();
1046 entry(b, "1 a");
1047 byte[] data = encodeASCII(b.toString());
1048 assertCorrupt("invalid mode 1", OBJ_TREE, data);
1049 assertSkipListRejects("invalid mode 1", OBJ_TREE, data);
1050 }
1051
1052 @Test
1053 public void testInvalidTreeModeNotSupportedMode2() {
1054 StringBuilder b = new StringBuilder();
1055 entry(b, "170000 a");
1056 assertCorrupt("invalid mode " + 0170000, OBJ_TREE, b);
1057 }
1058
1059 @Test
1060 public void testInvalidTreeModeMissingName() {
1061 StringBuilder b = new StringBuilder();
1062 b.append("100644");
1063 assertCorrupt("truncated in mode", OBJ_TREE, b);
1064 }
1065
1066 @Test
1067 public void testInvalidTreeNameContainsSlash()
1068 throws CorruptObjectException {
1069 StringBuilder b = new StringBuilder();
1070 entry(b, "100644 a/b");
1071 byte[] data = encodeASCII(b.toString());
1072 assertCorrupt("name contains '/'", OBJ_TREE, data);
1073 assertSkipListAccepts(OBJ_TREE, data);
1074 checker.setIgnore(FULL_PATHNAME, true);
1075 checker.checkTree(data);
1076 }
1077
1078 @Test
1079 public void testInvalidTreeNameIsEmpty() throws CorruptObjectException {
1080 StringBuilder b = new StringBuilder();
1081 entry(b, "100644 ");
1082 byte[] data = encodeASCII(b.toString());
1083 assertCorrupt("zero length name", OBJ_TREE, data);
1084 assertSkipListAccepts(OBJ_TREE, data);
1085 checker.setIgnore(EMPTY_NAME, true);
1086 checker.checkTree(data);
1087 }
1088
1089 @Test
1090 public void testInvalidTreeNameIsDot() throws CorruptObjectException {
1091 StringBuilder b = new StringBuilder();
1092 entry(b, "100644 .");
1093 byte[] data = encodeASCII(b.toString());
1094 assertCorrupt("invalid name '.'", OBJ_TREE, data);
1095 assertSkipListAccepts(OBJ_TREE, data);
1096 checker.setIgnore(HAS_DOT, true);
1097 checker.checkTree(data);
1098 }
1099
1100 @Test
1101 public void testInvalidTreeNameIsDotDot() throws CorruptObjectException {
1102 StringBuilder b = new StringBuilder();
1103 entry(b, "100644 ..");
1104 byte[] data = encodeASCII(b.toString());
1105 assertCorrupt("invalid name '..'", OBJ_TREE, data);
1106 assertSkipListAccepts(OBJ_TREE, data);
1107 checker.setIgnore(HAS_DOTDOT, true);
1108 checker.checkTree(data);
1109 }
1110
1111 @Test
1112 public void testInvalidTreeNameIsGit() throws CorruptObjectException {
1113 StringBuilder b = new StringBuilder();
1114 entry(b, "100644 .git");
1115 byte[] data = encodeASCII(b.toString());
1116 assertCorrupt("invalid name '.git'", OBJ_TREE, data);
1117 assertSkipListAccepts(OBJ_TREE, data);
1118 checker.setIgnore(HAS_DOTGIT, true);
1119 checker.checkTree(data);
1120 }
1121
1122 @Test
1123 public void testInvalidTreeNameIsMixedCaseGit()
1124 throws CorruptObjectException {
1125 StringBuilder b = new StringBuilder();
1126 entry(b, "100644 .GiT");
1127 byte[] data = encodeASCII(b.toString());
1128 assertCorrupt("invalid name '.GiT'", OBJ_TREE, data);
1129 assertSkipListAccepts(OBJ_TREE, data);
1130 checker.setIgnore(HAS_DOTGIT, true);
1131 checker.checkTree(data);
1132 }
1133
1134 @Test
1135 public void testInvalidTreeNameIsMacHFSGit() throws CorruptObjectException {
1136 StringBuilder b = new StringBuilder();
1137 entry(b, "100644 .gi\u200Ct");
1138 byte[] data = encode(b.toString());
1139
1140
1141 checker.checkTree(data);
1142
1143
1144 checker.setSafeForMacOS(true);
1145 assertCorrupt(
1146 "invalid name '.gi\u200Ct' contains ignorable Unicode characters",
1147 OBJ_TREE, data);
1148 assertSkipListAccepts(OBJ_TREE, data);
1149 checker.setIgnore(HAS_DOTGIT, true);
1150 checker.checkTree(data);
1151 }
1152
1153 @Test
1154 public void testInvalidTreeNameIsMacHFSGit2()
1155 throws CorruptObjectException {
1156 StringBuilder b = new StringBuilder();
1157 entry(b, "100644 \u206B.git");
1158 byte[] data = encode(b.toString());
1159
1160
1161 checker.checkTree(data);
1162
1163
1164 checker.setSafeForMacOS(true);
1165 assertCorrupt(
1166 "invalid name '\u206B.git' contains ignorable Unicode characters",
1167 OBJ_TREE, data);
1168 assertSkipListAccepts(OBJ_TREE, data);
1169 checker.setIgnore(HAS_DOTGIT, true);
1170 checker.checkTree(data);
1171 }
1172
1173 @Test
1174 public void testInvalidTreeNameIsMacHFSGit3()
1175 throws CorruptObjectException {
1176 StringBuilder b = new StringBuilder();
1177 entry(b, "100644 .git\uFEFF");
1178 byte[] data = encode(b.toString());
1179
1180
1181 checker.checkTree(data);
1182
1183
1184 checker.setSafeForMacOS(true);
1185 assertCorrupt(
1186 "invalid name '.git\uFEFF' contains ignorable Unicode characters",
1187 OBJ_TREE, data);
1188 assertSkipListAccepts(OBJ_TREE, data);
1189 checker.setIgnore(HAS_DOTGIT, true);
1190 checker.checkTree(data);
1191 }
1192
1193
1194
1195 @Test
1196 public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd()
1197 throws CorruptObjectException {
1198 byte[] data = concat(encode("100644 .git"),
1199 new byte[] { (byte) 0xef });
1200 StringBuilder b = new StringBuilder();
1201 entry(b, "");
1202 data = concat(data, encode(b.toString()));
1203
1204
1205 checker.checkTree(data);
1206
1207
1208 checker.setSafeForMacOS(true);
1209 assertCorrupt(
1210 "invalid name contains byte sequence '0xef' which is not a valid UTF-8 character",
1211 OBJ_TREE, data);
1212 assertSkipListAccepts(OBJ_TREE, data);
1213 }
1214
1215 @Test
1216 public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd2()
1217 throws CorruptObjectException {
1218 byte[] data = concat(encode("100644 .git"),
1219 new byte[] {
1220 (byte) 0xe2, (byte) 0xab });
1221 StringBuilder b = new StringBuilder();
1222 entry(b, "");
1223 data = concat(data, encode(b.toString()));
1224
1225
1226 checker.checkTree(data);
1227
1228
1229 checker.setSafeForMacOS(true);
1230 assertCorrupt(
1231 "invalid name contains byte sequence '0xe2ab' which is not a valid UTF-8 character",
1232 OBJ_TREE, data);
1233 assertSkipListAccepts(OBJ_TREE, data);
1234 }
1235
1236 @Test
1237 public void testInvalidTreeNameIsNotMacHFSGit()
1238 throws CorruptObjectException {
1239 StringBuilder b = new StringBuilder();
1240 entry(b, "100644 .git\u200Cx");
1241 byte[] data = encode(b.toString());
1242 checker.setSafeForMacOS(true);
1243 checker.checkTree(data);
1244 }
1245
1246 @Test
1247 public void testInvalidTreeNameIsNotMacHFSGit2()
1248 throws CorruptObjectException {
1249 StringBuilder b = new StringBuilder();
1250 entry(b, "100644 .kit\u200C");
1251 byte[] data = encode(b.toString());
1252 checker.setSafeForMacOS(true);
1253 checker.checkTree(data);
1254 }
1255
1256 @Test
1257 public void testInvalidTreeNameIsNotMacHFSGitOtherPlatform()
1258 throws CorruptObjectException {
1259 StringBuilder b = new StringBuilder();
1260 entry(b, "100644 .git\u200C");
1261 byte[] data = encode(b.toString());
1262 checker.checkTree(data);
1263 }
1264
1265 @Test
1266 public void testInvalidTreeNameIsDotGitDot() throws CorruptObjectException {
1267 StringBuilder b = new StringBuilder();
1268 entry(b, "100644 .git.");
1269 byte[] data = encodeASCII(b.toString());
1270 assertCorrupt("invalid name '.git.'", OBJ_TREE, data);
1271 assertSkipListAccepts(OBJ_TREE, data);
1272 checker.setIgnore(HAS_DOTGIT, true);
1273 checker.checkTree(data);
1274 }
1275
1276 @Test
1277 public void testValidTreeNameIsDotGitDotDot()
1278 throws CorruptObjectException {
1279 StringBuilder b = new StringBuilder();
1280 entry(b, "100644 .git..");
1281 checker.checkTree(encodeASCII(b.toString()));
1282 }
1283
1284 @Test
1285 public void testInvalidTreeNameIsDotGitSpace()
1286 throws CorruptObjectException {
1287 StringBuilder b = new StringBuilder();
1288 entry(b, "100644 .git ");
1289 byte[] data = encodeASCII(b.toString());
1290 assertCorrupt("invalid name '.git '", OBJ_TREE, data);
1291 assertSkipListAccepts(OBJ_TREE, data);
1292 checker.setIgnore(HAS_DOTGIT, true);
1293 checker.checkTree(data);
1294 }
1295
1296 @Test
1297 public void testInvalidTreeNameIsDotGitSomething()
1298 throws CorruptObjectException {
1299 StringBuilder b = new StringBuilder();
1300 entry(b, "100644 .gitfoobar");
1301 byte[] data = encodeASCII(b.toString());
1302 checker.checkTree(data);
1303 }
1304
1305 @Test
1306 public void testInvalidTreeNameIsDotGitSomethingSpaceSomething()
1307 throws CorruptObjectException {
1308 StringBuilder b = new StringBuilder();
1309 entry(b, "100644 .gitfoo bar");
1310 byte[] data = encodeASCII(b.toString());
1311 checker.checkTree(data);
1312 }
1313
1314 @Test
1315 public void testInvalidTreeNameIsDotGitSomethingDot()
1316 throws CorruptObjectException {
1317 StringBuilder b = new StringBuilder();
1318 entry(b, "100644 .gitfoobar.");
1319 byte[] data = encodeASCII(b.toString());
1320 checker.checkTree(data);
1321 }
1322
1323 @Test
1324 public void testInvalidTreeNameIsDotGitSomethingDotDot()
1325 throws CorruptObjectException {
1326 StringBuilder b = new StringBuilder();
1327 entry(b, "100644 .gitfoobar..");
1328 byte[] data = encodeASCII(b.toString());
1329 checker.checkTree(data);
1330 }
1331
1332 @Test
1333 public void testInvalidTreeNameIsDotGitDotSpace()
1334 throws CorruptObjectException {
1335 StringBuilder b = new StringBuilder();
1336 entry(b, "100644 .git. ");
1337 byte[] data = encodeASCII(b.toString());
1338 assertCorrupt("invalid name '.git. '", OBJ_TREE, data);
1339 assertSkipListAccepts(OBJ_TREE, data);
1340 checker.setIgnore(HAS_DOTGIT, true);
1341 checker.checkTree(data);
1342 }
1343
1344 @Test
1345 public void testInvalidTreeNameIsDotGitSpaceDot()
1346 throws CorruptObjectException {
1347 StringBuilder b = new StringBuilder();
1348 entry(b, "100644 .git . ");
1349 byte[] data = encodeASCII(b.toString());
1350 assertCorrupt("invalid name '.git . '", OBJ_TREE, data);
1351 assertSkipListAccepts(OBJ_TREE, data);
1352 checker.setIgnore(HAS_DOTGIT, true);
1353 checker.checkTree(data);
1354 }
1355
1356 @Test
1357 public void testInvalidTreeNameIsGITTilde1() throws CorruptObjectException {
1358 StringBuilder b = new StringBuilder();
1359 entry(b, "100644 GIT~1");
1360 byte[] data = encodeASCII(b.toString());
1361 assertCorrupt("invalid name 'GIT~1'", OBJ_TREE, data);
1362 assertSkipListAccepts(OBJ_TREE, data);
1363 checker.setIgnore(HAS_DOTGIT, true);
1364 checker.checkTree(data);
1365 }
1366
1367 @Test
1368 public void testInvalidTreeNameIsGiTTilde1() throws CorruptObjectException {
1369 StringBuilder b = new StringBuilder();
1370 entry(b, "100644 GiT~1");
1371 byte[] data = encodeASCII(b.toString());
1372 assertCorrupt("invalid name 'GiT~1'", OBJ_TREE, data);
1373 assertSkipListAccepts(OBJ_TREE, data);
1374 checker.setIgnore(HAS_DOTGIT, true);
1375 checker.checkTree(data);
1376 }
1377
1378 @Test
1379 public void testValidTreeNameIsGitTilde11() throws CorruptObjectException {
1380 StringBuilder b = new StringBuilder();
1381 entry(b, "100644 GIT~11");
1382 byte[] data = encodeASCII(b.toString());
1383 checker.checkTree(data);
1384 }
1385
1386 @Test
1387 public void testInvalidTreeTruncatedInName() {
1388 StringBuilder b = new StringBuilder();
1389 b.append("100644 b");
1390 byte[] data = encodeASCII(b.toString());
1391 assertCorrupt("truncated in name", OBJ_TREE, data);
1392 assertSkipListRejects("truncated in name", OBJ_TREE, data);
1393 }
1394
1395 @Test
1396 public void testInvalidTreeTruncatedInObjectId() {
1397 StringBuilder b = new StringBuilder();
1398 b.append("100644 b\0\1\2");
1399 byte[] data = encodeASCII(b.toString());
1400 assertCorrupt("truncated in object id", OBJ_TREE, data);
1401 assertSkipListRejects("truncated in object id", OBJ_TREE, data);
1402 }
1403
1404 @Test
1405 public void testInvalidTreeBadSorting1() throws CorruptObjectException {
1406 StringBuilder b = new StringBuilder();
1407 entry(b, "100644 foobar");
1408 entry(b, "100644 fooaaa");
1409 byte[] data = encodeASCII(b.toString());
1410
1411 assertCorrupt("incorrectly sorted", OBJ_TREE, data);
1412
1413 ObjectId id = idFor(OBJ_TREE, data);
1414 try {
1415 checker.check(id, OBJ_TREE, data);
1416 fail("Did not throw CorruptObjectException");
1417 } catch (CorruptObjectException e) {
1418 assertSame(TREE_NOT_SORTED, e.getErrorType());
1419 assertEquals("treeNotSorted: object " + id.name()
1420 + ": incorrectly sorted", e.getMessage());
1421 }
1422
1423 assertSkipListAccepts(OBJ_TREE, data);
1424 checker.setIgnore(TREE_NOT_SORTED, true);
1425 checker.checkTree(data);
1426 }
1427
1428 @Test
1429 public void testInvalidTreeBadSorting2() throws CorruptObjectException {
1430 StringBuilder b = new StringBuilder();
1431 entry(b, "40000 a");
1432 entry(b, "100644 a.c");
1433 byte[] data = encodeASCII(b.toString());
1434 assertCorrupt("incorrectly sorted", OBJ_TREE, data);
1435 assertSkipListAccepts(OBJ_TREE, data);
1436 checker.setIgnore(TREE_NOT_SORTED, true);
1437 checker.checkTree(data);
1438 }
1439
1440 @Test
1441 public void testInvalidTreeBadSorting3() throws CorruptObjectException {
1442 StringBuilder b = new StringBuilder();
1443 entry(b, "100644 a0c");
1444 entry(b, "40000 a");
1445 byte[] data = encodeASCII(b.toString());
1446 assertCorrupt("incorrectly sorted", OBJ_TREE, data);
1447 assertSkipListAccepts(OBJ_TREE, data);
1448 checker.setIgnore(TREE_NOT_SORTED, true);
1449 checker.checkTree(data);
1450 }
1451
1452 @Test
1453 public void testInvalidTreeDuplicateNames1_File()
1454 throws CorruptObjectException {
1455 StringBuilder b = new StringBuilder();
1456 entry(b, "100644 a");
1457 entry(b, "100644 a");
1458 byte[] data = encodeASCII(b.toString());
1459 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1460 assertSkipListAccepts(OBJ_TREE, data);
1461 checker.setIgnore(DUPLICATE_ENTRIES, true);
1462 checker.checkTree(data);
1463 }
1464
1465 @Test
1466 public void testInvalidTreeDuplicateNames1_Tree()
1467 throws CorruptObjectException {
1468 StringBuilder b = new StringBuilder();
1469 entry(b, "40000 a");
1470 entry(b, "40000 a");
1471 byte[] data = encodeASCII(b.toString());
1472 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1473 assertSkipListAccepts(OBJ_TREE, data);
1474 checker.setIgnore(DUPLICATE_ENTRIES, true);
1475 checker.checkTree(data);
1476 }
1477
1478 @Test
1479 public void testInvalidTreeDuplicateNames2() throws CorruptObjectException {
1480 StringBuilder b = new StringBuilder();
1481 entry(b, "100644 a");
1482 entry(b, "100755 a");
1483 byte[] data = encodeASCII(b.toString());
1484 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1485 assertSkipListAccepts(OBJ_TREE, data);
1486 checker.setIgnore(DUPLICATE_ENTRIES, true);
1487 checker.checkTree(data);
1488 }
1489
1490 @Test
1491 public void testInvalidTreeDuplicateNames3() throws CorruptObjectException {
1492 StringBuilder b = new StringBuilder();
1493 entry(b, "100644 a");
1494 entry(b, "40000 a");
1495 byte[] data = encodeASCII(b.toString());
1496 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1497 assertSkipListAccepts(OBJ_TREE, data);
1498 checker.setIgnore(DUPLICATE_ENTRIES, true);
1499 checker.checkTree(data);
1500 }
1501
1502 @Test
1503 public void testInvalidTreeDuplicateNames4() throws CorruptObjectException {
1504 StringBuilder b = new StringBuilder();
1505 entry(b, "100644 a");
1506 entry(b, "100644 a.c");
1507 entry(b, "100644 a.d");
1508 entry(b, "100644 a.e");
1509 entry(b, "40000 a");
1510 entry(b, "100644 zoo");
1511 byte[] data = encodeASCII(b.toString());
1512 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1513 assertSkipListAccepts(OBJ_TREE, data);
1514 checker.setIgnore(DUPLICATE_ENTRIES, true);
1515 checker.checkTree(data);
1516 }
1517
1518 @Test
1519 public void testInvalidTreeDuplicateNames5()
1520 throws CorruptObjectException {
1521 StringBuilder b = new StringBuilder();
1522 entry(b, "100644 A");
1523 entry(b, "100644 a");
1524 byte[] data = b.toString().getBytes(UTF_8);
1525 checker.setSafeForWindows(true);
1526 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1527 assertSkipListAccepts(OBJ_TREE, data);
1528 checker.setIgnore(DUPLICATE_ENTRIES, true);
1529 checker.checkTree(data);
1530 }
1531
1532 @Test
1533 public void testInvalidTreeDuplicateNames6()
1534 throws CorruptObjectException {
1535 StringBuilder b = new StringBuilder();
1536 entry(b, "100644 A");
1537 entry(b, "100644 a");
1538 byte[] data = b.toString().getBytes(UTF_8);
1539 checker.setSafeForMacOS(true);
1540 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1541 assertSkipListAccepts(OBJ_TREE, data);
1542 checker.setIgnore(DUPLICATE_ENTRIES, true);
1543 checker.checkTree(data);
1544 }
1545
1546 @Test
1547 public void testInvalidTreeDuplicateNames7()
1548 throws CorruptObjectException {
1549 StringBuilder b = new StringBuilder();
1550 entry(b, "100644 \u0065\u0301");
1551 entry(b, "100644 \u00e9");
1552 byte[] data = b.toString().getBytes(UTF_8);
1553 checker.setSafeForMacOS(true);
1554 assertCorrupt("duplicate entry names", OBJ_TREE, data);
1555 assertSkipListAccepts(OBJ_TREE, data);
1556 checker.setIgnore(DUPLICATE_ENTRIES, true);
1557 checker.checkTree(data);
1558 }
1559
1560 @Test
1561 public void testInvalidTreeDuplicateNames8()
1562 throws CorruptObjectException {
1563 StringBuilder b = new StringBuilder();
1564 entry(b, "100644 A");
1565 checker.setSafeForMacOS(true);
1566 checker.checkTree(b.toString().getBytes(UTF_8));
1567 }
1568
1569 @Test
1570 public void testRejectNulInPathSegment() {
1571 try {
1572 checker.checkPathSegment(encodeASCII("a\u0000b"), 0, 3);
1573 fail("incorrectly accepted NUL in middle of name");
1574 } catch (CorruptObjectException e) {
1575 assertEquals("name contains byte 0x00", e.getMessage());
1576 }
1577 }
1578
1579 @Test
1580 public void testRejectSpaceAtEndOnWindows() {
1581 checker.setSafeForWindows(true);
1582 try {
1583 checkOneName("test ");
1584 fail("incorrectly accepted space at end");
1585 } catch (CorruptObjectException e) {
1586 assertEquals("invalid name ends with ' '", e.getMessage());
1587 }
1588 }
1589
1590 @Test
1591 public void testBug477090() throws CorruptObjectException {
1592 checker.setSafeForMacOS(true);
1593 final byte[] bytes = {
1594
1595 (byte) 0xe2, (byte) 0x88, (byte) 0x9e,
1596
1597 0x2e, 0x68, 0x74, 0x6d, 0x6c };
1598 checker.checkPathSegment(bytes, 0, bytes.length);
1599 }
1600
1601 @Test
1602 public void testRejectDotAtEndOnWindows() {
1603 checker.setSafeForWindows(true);
1604 try {
1605 checkOneName("test.");
1606 fail("incorrectly accepted dot at end");
1607 } catch (CorruptObjectException e) {
1608 assertEquals("invalid name ends with '.'", e.getMessage());
1609 }
1610 }
1611
1612 @Test
1613 public void testRejectDevicesOnWindows() {
1614 checker.setSafeForWindows(true);
1615
1616 String[] bad = { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3",
1617 "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2",
1618 "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" };
1619 for (String b : bad) {
1620 try {
1621 checkOneName(b);
1622 fail("incorrectly accepted " + b);
1623 } catch (CorruptObjectException e) {
1624 assertEquals("invalid name '" + b + "'", e.getMessage());
1625 }
1626 try {
1627 checkOneName(b + ".txt");
1628 fail("incorrectly accepted " + b + ".txt");
1629 } catch (CorruptObjectException e) {
1630 assertEquals("invalid name '" + b + "'", e.getMessage());
1631 }
1632 }
1633 }
1634
1635 @Test
1636 public void testRejectInvalidWindowsCharacters() {
1637 checker.setSafeForWindows(true);
1638 rejectName('<');
1639 rejectName('>');
1640 rejectName(':');
1641 rejectName('"');
1642 rejectName('\\');
1643 rejectName('|');
1644 rejectName('?');
1645 rejectName('*');
1646
1647 for (int i = 1; i <= 31; i++)
1648 rejectName((byte) i);
1649 }
1650
1651 private void rejectName(char c) {
1652 try {
1653 checkOneName("te" + c + "st");
1654 fail("incorrectly accepted with " + c);
1655 } catch (CorruptObjectException e) {
1656
1657 assertEquals("char '" + c + "' not allowed in Windows filename", e.getMessage());
1658 }
1659 }
1660
1661 private void rejectName(byte c) {
1662 String h = Integer.toHexString(c);
1663 try {
1664 checkOneName("te" + ((char) c) + "st");
1665 fail("incorrectly accepted with 0x" + h);
1666 } catch (CorruptObjectException e) {
1667 assertEquals("byte 0x" + h + " not allowed in Windows filename", e.getMessage());
1668 }
1669 }
1670
1671
1672 @Test
1673 public void testRejectInvalidCharacter() {
1674 try {
1675 checkOneName("te/st");
1676 fail("incorrectly accepted with /");
1677 } catch (CorruptObjectException e) {
1678
1679 assertEquals("name contains '/'", e.getMessage());
1680 }
1681 }
1682
1683 private void checkOneName(String name) throws CorruptObjectException {
1684 StringBuilder b = new StringBuilder();
1685 entry(b, "100644 " + name);
1686 checker.checkTree(encodeASCII(b.toString()));
1687 }
1688
1689
1690
1691
1692 private static ObjectId entry(StringBuilder b, String modeName) {
1693 byte[] id = new byte[OBJECT_ID_LENGTH];
1694
1695 b.append(modeName);
1696 b.append('\0');
1697 for (int i = 0; i < OBJECT_ID_LENGTH; i++) {
1698 b.append((char) i);
1699 id[i] = (byte) i;
1700 }
1701
1702 return ObjectId.fromRaw(id);
1703 }
1704
1705 private void assertCorrupt(String msg, int type, StringBuilder b) {
1706 assertCorrupt(msg, type, encodeASCII(b.toString()));
1707 }
1708
1709 private void assertCorrupt(String msg, int type, byte[] data) {
1710 try {
1711 checker.check(type, data);
1712 fail("Did not throw CorruptObjectException");
1713 } catch (CorruptObjectException e) {
1714 assertEquals(msg, e.getMessage());
1715 }
1716 }
1717
1718 private void assertSkipListAccepts(int type, byte[] data)
1719 throws CorruptObjectException {
1720 ObjectId id = idFor(type, data);
1721 checker.setSkipList(set(id));
1722 checker.check(id, type, data);
1723 checker.setSkipList(null);
1724 }
1725
1726 private void assertSkipListRejects(String msg, int type, byte[] data) {
1727 ObjectId id = idFor(type, data);
1728 checker.setSkipList(set(id));
1729 try {
1730 checker.check(id, type, data);
1731 fail("Did not throw CorruptObjectException");
1732 } catch (CorruptObjectException e) {
1733 assertEquals(msg, e.getMessage());
1734 }
1735 checker.setSkipList(null);
1736 }
1737
1738 private static ObjectIdSet set(ObjectId... ids) {
1739 return (AnyObjectId objectId) -> {
1740 for (ObjectId id : ids) {
1741 if (id.equals(objectId)) {
1742 return true;
1743 }
1744 }
1745 return false;
1746 };
1747 }
1748
1749 @SuppressWarnings("resource")
1750 private static ObjectId idFor(int type, byte[] raw) {
1751 return new ObjectInserter.Formatter().idFor(type, raw);
1752 }
1753 }