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