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