1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.revwalk;
12
13 import static java.nio.charset.StandardCharsets.ISO_8859_1;
14 import static java.nio.charset.StandardCharsets.UTF_8;
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.assertNotNull;
17 import static org.junit.Assert.assertNull;
18 import static org.junit.Assert.assertSame;
19 import static org.junit.Assert.assertTrue;
20 import static org.junit.Assert.fail;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.UnsupportedEncodingException;
24 import java.nio.charset.IllegalCharsetNameException;
25 import java.nio.charset.UnsupportedCharsetException;
26 import java.util.TimeZone;
27
28 import org.eclipse.jgit.junit.RepositoryTestCase;
29 import org.eclipse.jgit.lib.CommitBuilder;
30 import org.eclipse.jgit.lib.Constants;
31 import org.eclipse.jgit.lib.ObjectId;
32 import org.eclipse.jgit.lib.ObjectInserter;
33 import org.eclipse.jgit.lib.PersonIdent;
34 import org.junit.Test;
35
36 public class RevCommitParseTest extends RepositoryTestCase {
37 @Test
38 public void testParse_NoParents() throws Exception {
39 final ObjectId treeId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
40 final String authorName = "A U. Thor";
41 final String authorEmail = "a_u_thor@example.com";
42 final int authorTime = 1218123387;
43 final String authorTimeZone = "+0700";
44
45 final String committerName = "C O. Miter";
46 final String committerEmail = "comiter@example.com";
47 final int committerTime = 1218123390;
48 final String committerTimeZone = "-0500";
49 final StringBuilder body = new StringBuilder();
50
51 body.append("tree ");
52 body.append(treeId.name());
53 body.append("\n");
54
55 body.append("author ");
56 body.append(authorName);
57 body.append(" <");
58 body.append(authorEmail);
59 body.append("> ");
60 body.append(authorTime);
61 body.append(" ");
62 body.append(authorTimeZone);
63 body.append(" \n");
64
65 body.append("committer ");
66 body.append(committerName);
67 body.append(" <");
68 body.append(committerEmail);
69 body.append("> ");
70 body.append(committerTime);
71 body.append(" ");
72 body.append(committerTimeZone);
73 body.append("\n");
74
75 body.append("\n");
76
77 final RevCommit c;
78
79 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
80 assertNull(c.getTree());
81 assertNull(c.getParents());
82
83 try (RevWalk rw = new RevWalk(db)) {
84 c.parseCanonical(rw, body.toString().getBytes(UTF_8));
85 assertNotNull(c.getTree());
86 assertEquals(treeId, c.getTree().getId());
87 assertSame(rw.lookupTree(treeId), c.getTree());
88 }
89 assertNotNull(c.getParents());
90 assertEquals(0, c.getParentCount());
91 assertEquals("", c.getFullMessage());
92
93 final PersonIdent cAuthor = c.getAuthorIdent();
94 assertNotNull(cAuthor);
95 assertEquals(authorName, cAuthor.getName());
96 assertEquals(authorEmail, cAuthor.getEmailAddress());
97 assertEquals((long) authorTime * 1000, cAuthor.getWhen().getTime());
98 assertEquals(TimeZone.getTimeZone("GMT" + authorTimeZone),
99 cAuthor.getTimeZone());
100
101 final PersonIdent cCommitter = c.getCommitterIdent();
102 assertNotNull(cCommitter);
103 assertEquals(committerName, cCommitter.getName());
104 assertEquals(committerEmail, cCommitter.getEmailAddress());
105 assertEquals((long) committerTime * 1000,
106 cCommitter.getWhen().getTime());
107 assertEquals(TimeZone.getTimeZone("GMT" + committerTimeZone),
108 cCommitter.getTimeZone());
109 }
110
111 private RevCommit create(String msg) throws Exception {
112 final StringBuilder b = new StringBuilder();
113 b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
114 b.append("author A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
115 b.append("committer C O. Miter <c@example.com> 1218123390 -0500\n");
116 b.append("\n");
117 b.append(msg);
118
119 final RevCommit c;
120 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
121 try (RevWalk rw = new RevWalk(db)) {
122 c.parseCanonical(rw, b.toString().getBytes(UTF_8));
123 return c;
124 }
125 }
126
127 @Test
128 public void testParse_WeirdHeaderOnlyCommit() throws Exception {
129 final StringBuilder b = new StringBuilder();
130 b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
131 b.append("author A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
132 b.append("committer C O. Miter <c@example.com> 1218123390 -0500\n");
133
134 final RevCommit c;
135 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
136 try (RevWalk rw = new RevWalk(db)) {
137 c.parseCanonical(rw, b.toString().getBytes(UTF_8));
138 }
139 assertEquals("", c.getFullMessage());
140 assertEquals("", c.getShortMessage());
141 }
142
143 @Test
144 public void testParse_incompleteAuthorAndCommitter() throws Exception {
145 final StringBuilder b = new StringBuilder();
146 b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
147 b.append("author <a_u_thor@example.com> 1218123387 +0700\n");
148 b.append("committer <> 1218123390 -0500\n");
149
150 final RevCommit c;
151 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
152 try (RevWalk rw = new RevWalk(db)) {
153 c.parseCanonical(rw, b.toString().getBytes(UTF_8));
154 }
155 assertEquals(
156 new PersonIdent("", "a_u_thor@example.com", 1218123387000l, 7),
157 c.getAuthorIdent());
158 assertEquals(new PersonIdent("", "", 1218123390000l, -5),
159 c.getCommitterIdent());
160 }
161
162 @Test
163 public void testParse_implicit_UTF8_encoded() throws Exception {
164 final ByteArrayOutputStream b = new ByteArrayOutputStream();
165 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
166 .getBytes(UTF_8));
167 b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
168 .getBytes(UTF_8));
169 b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n"
170 .getBytes(UTF_8));
171 b.write("\n".getBytes(UTF_8));
172 b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8));
173 b.write("\n".getBytes(UTF_8));
174 b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
175 final RevCommit c;
176 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
177 try (RevWalk rw = new RevWalk(db)) {
178 c.parseCanonical(rw, b.toByteArray());
179 }
180 assertSame(UTF_8, c.getEncoding());
181 assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
182 assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
183 assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n",
184 c.getFullMessage());
185 }
186
187 @Test
188 public void testParse_implicit_mixed_encoded() throws Exception {
189 final ByteArrayOutputStream b = new ByteArrayOutputStream();
190 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
191 .getBytes(UTF_8));
192 b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
193 .getBytes(ISO_8859_1));
194 b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n"
195 .getBytes(UTF_8));
196 b.write("\n".getBytes(UTF_8));
197 b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8));
198 b.write("\n".getBytes(UTF_8));
199 b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
200 final RevCommit c;
201 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
202 try (RevWalk rw = new RevWalk(db)) {
203 c.parseCanonical(rw, b.toByteArray());
204 }
205 assertSame(UTF_8, c.getEncoding());
206 assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
207 assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
208 assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n",
209 c.getFullMessage());
210 }
211
212
213
214
215
216
217 @Test
218 public void testParse_explicit_encoded() throws Exception {
219 final ByteArrayOutputStream b = new ByteArrayOutputStream();
220 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
221 .getBytes("EUC-JP"));
222 b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
223 .getBytes("EUC-JP"));
224 b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n"
225 .getBytes("EUC-JP"));
226 b.write("encoding euc_JP\n".getBytes("EUC-JP"));
227 b.write("\n".getBytes("EUC-JP"));
228 b.write("\u304d\u308c\u3044\n".getBytes("EUC-JP"));
229 b.write("\n".getBytes("EUC-JP"));
230 b.write("Hi\n".getBytes("EUC-JP"));
231 final RevCommit c;
232 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
233 try (RevWalk rw = new RevWalk(db)) {
234 c.parseCanonical(rw, b.toByteArray());
235 }
236
237 assertEquals("EUC-JP", c.getEncoding().name());
238 assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
239 assertEquals("\u304d\u308c\u3044", c.getShortMessage());
240 assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
241 }
242
243
244
245
246
247
248
249
250
251
252 @Test
253 public void testParse_explicit_bad_encoded() throws Exception {
254 final ByteArrayOutputStream b = new ByteArrayOutputStream();
255 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
256 .getBytes(UTF_8));
257 b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
258 .getBytes(ISO_8859_1));
259 b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n"
260 .getBytes(UTF_8));
261 b.write("encoding EUC-JP\n".getBytes(UTF_8));
262 b.write("\n".getBytes(UTF_8));
263 b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
264 b.write("\n".getBytes(UTF_8));
265 b.write("Hi\n".getBytes(UTF_8));
266 final RevCommit c;
267 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
268 try (RevWalk rw = new RevWalk(db)) {
269 c.parseCanonical(rw, b.toByteArray());
270 }
271
272 assertEquals("EUC-JP", c.getEncoding().name());
273 assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
274 assertEquals("\u304d\u308c\u3044", c.getShortMessage());
275 assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289 @Test
290 public void testParse_explicit_bad_encoded2() throws Exception {
291 final ByteArrayOutputStream b = new ByteArrayOutputStream();
292 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
293 .getBytes(UTF_8));
294 b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
295 .getBytes(UTF_8));
296 b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n"
297 .getBytes(UTF_8));
298 b.write("encoding ISO-8859-1\n".getBytes(UTF_8));
299 b.write("\n".getBytes(UTF_8));
300 b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
301 b.write("\n".getBytes(UTF_8));
302 b.write("Hi\n".getBytes(UTF_8));
303 final RevCommit c;
304 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
305 try (RevWalk rw = new RevWalk(db)) {
306 c.parseCanonical(rw, b.toByteArray());
307 }
308
309 assertEquals("ISO-8859-1", c.getEncoding().name());
310 assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
311 assertEquals("\u304d\u308c\u3044", c.getShortMessage());
312 assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
313 }
314
315 @Test
316 public void testParse_incorrectUtf8Name() throws Exception {
317 ByteArrayOutputStream b = new ByteArrayOutputStream();
318 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
319 .getBytes(UTF_8));
320 b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
321 b.write("committer co <c@example.com> 1218123390 -0500\n"
322 .getBytes(UTF_8));
323 b.write("encoding 'utf8'\n".getBytes(UTF_8));
324 b.write("\n".getBytes(UTF_8));
325 b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8));
326
327 RevCommit c = new RevCommit(
328 id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
329 try (RevWalk rw = new RevWalk(db)) {
330 c.parseCanonical(rw, b.toByteArray());
331 }
332 assertEquals("'utf8'", c.getEncodingName());
333 assertEquals("Sm\u00f6rg\u00e5sbord\n", c.getFullMessage());
334
335 try {
336 c.getEncoding();
337 fail("Expected " + IllegalCharsetNameException.class);
338 } catch (IllegalCharsetNameException badName) {
339 assertEquals("'utf8'", badName.getMessage());
340 }
341 }
342
343 @Test
344 public void testParse_illegalEncoding() throws Exception {
345 ByteArrayOutputStream b = new ByteArrayOutputStream();
346 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
347 .getBytes(UTF_8));
348 b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
349 b.write("committer co <c@example.com> 1218123390 -0500\n"
350 .getBytes(UTF_8));
351 b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8));
352 b.write("\n".getBytes(UTF_8));
353 b.write("message\n".getBytes(UTF_8));
354
355 RevCommit c = new RevCommit(
356 id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
357 try (RevWalk rw = new RevWalk(db)) {
358 c.parseCanonical(rw, b.toByteArray());
359 }
360 assertEquals("utf-8logoutputencoding=gbk", c.getEncodingName());
361 assertEquals("message\n", c.getFullMessage());
362 assertEquals("message", c.getShortMessage());
363 assertTrue(c.getFooterLines().isEmpty());
364 assertEquals("au", c.getAuthorIdent().getName());
365
366 try {
367 c.getEncoding();
368 fail("Expected " + IllegalCharsetNameException.class);
369 } catch (IllegalCharsetNameException badName) {
370 assertEquals("utf-8logoutputencoding=gbk", badName.getMessage());
371 }
372 }
373
374 @Test
375 public void testParse_unsupportedEncoding() throws Exception {
376 ByteArrayOutputStream b = new ByteArrayOutputStream();
377 b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
378 .getBytes(UTF_8));
379 b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8));
380 b.write("committer co <c@example.com> 1218123390 -0500\n"
381 .getBytes(UTF_8));
382 b.write("encoding it_IT.UTF8\n".getBytes(UTF_8));
383 b.write("\n".getBytes(UTF_8));
384 b.write("message\n".getBytes(UTF_8));
385
386 RevCommit c = new RevCommit(
387 id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
388 try (RevWalk rw = new RevWalk(db)) {
389 c.parseCanonical(rw, b.toByteArray());
390 }
391 assertEquals("it_IT.UTF8", c.getEncodingName());
392 assertEquals("message\n", c.getFullMessage());
393 assertEquals("message", c.getShortMessage());
394 assertTrue(c.getFooterLines().isEmpty());
395 assertEquals("au", c.getAuthorIdent().getName());
396
397 try {
398 c.getEncoding();
399 fail("Expected " + UnsupportedCharsetException.class);
400 } catch (UnsupportedCharsetException badName) {
401 assertEquals("it_IT.UTF8", badName.getMessage());
402 }
403 }
404
405 @Test
406 public void testParse_NoMessage() throws Exception {
407 final String msg = "";
408 final RevCommit c = create(msg);
409 assertEquals(msg, c.getFullMessage());
410 assertEquals(msg, c.getShortMessage());
411 }
412
413 @Test
414 public void testParse_OnlyLFMessage() throws Exception {
415 final RevCommit c = create("\n");
416 assertEquals("\n", c.getFullMessage());
417 assertEquals("", c.getShortMessage());
418 }
419
420 @Test
421 public void testParse_ShortLineOnlyNoLF() throws Exception {
422 final String shortMsg = "This is a short message.";
423 final RevCommit c = create(shortMsg);
424 assertEquals(shortMsg, c.getFullMessage());
425 assertEquals(shortMsg, c.getShortMessage());
426 }
427
428 @Test
429 public void testParse_ShortLineOnlyEndLF() throws Exception {
430 final String shortMsg = "This is a short message.";
431 final String fullMsg = shortMsg + "\n";
432 final RevCommit c = create(fullMsg);
433 assertEquals(fullMsg, c.getFullMessage());
434 assertEquals(shortMsg, c.getShortMessage());
435 }
436
437 @Test
438 public void testParse_ShortLineOnlyEmbeddedLF() throws Exception {
439 final String fullMsg = "This is a\nshort message.";
440 final String shortMsg = fullMsg.replace('\n', ' ');
441 final RevCommit c = create(fullMsg);
442 assertEquals(fullMsg, c.getFullMessage());
443 assertEquals(shortMsg, c.getShortMessage());
444 }
445
446 @Test
447 public void testParse_ShortLineOnlyEmbeddedAndEndingLF() throws Exception {
448 final String fullMsg = "This is a\nshort message.\n";
449 final String shortMsg = "This is a short message.";
450 final RevCommit c = create(fullMsg);
451 assertEquals(fullMsg, c.getFullMessage());
452 assertEquals(shortMsg, c.getShortMessage());
453 }
454
455 @Test
456 public void testParse_GitStyleMessage() throws Exception {
457 final String shortMsg = "This fixes a bug.";
458 final String body = "We do it with magic and pixie dust and stuff.\n"
459 + "\n" + "Signed-off-by: A U. Thor <author@example.com>\n";
460 final String fullMsg = shortMsg + "\n" + "\n" + body;
461 final RevCommit c = create(fullMsg);
462 assertEquals(fullMsg, c.getFullMessage());
463 assertEquals(shortMsg, c.getShortMessage());
464 }
465
466 @Test
467 public void testParse_PublicParseMethod()
468 throws UnsupportedEncodingException {
469 CommitBuilder src = new CommitBuilder();
470 try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
471 src.setTreeId(fmt.idFor(Constants.OBJ_TREE, new byte[] {}));
472 }
473 src.setAuthor(author);
474 src.setCommitter(committer);
475 src.setMessage("Test commit\n\nThis is a test.\n");
476
477 RevCommit p = RevCommit.parse(src.build());
478 assertEquals(src.getTreeId(), p.getTree());
479 assertEquals(0, p.getParentCount());
480 assertEquals(author, p.getAuthorIdent());
481 assertEquals(committer, p.getCommitterIdent());
482 assertEquals("Test commit", p.getShortMessage());
483 assertEquals(src.getMessage(), p.getFullMessage());
484 }
485
486 @Test
487 public void testParse_GitStyleMessageWithCRLF() throws Exception {
488 final String shortMsgIn = "This fixes a\r\nbug.\r\n\r\n";
489 final String shortMsg = "This fixes a bug.";
490 final String body = "We do it with magic and pixie dust\r\nand stuff.\r\n"
491 + "\r\n\r\n"
492 + "Signed-off-by: A U. Thor <author@example.com>\r\n";
493 final String fullMsg = shortMsgIn + "\r\n" + "\r\n" + body;
494 final RevCommit c = create(fullMsg);
495 assertEquals(fullMsg, c.getFullMessage());
496 assertEquals(shortMsg, c.getShortMessage());
497 }
498
499 private static ObjectId id(String str) {
500 return ObjectId.fromString(str);
501 }
502
503 @Test
504 public void testParse_gpgSig() throws Exception {
505 String commit = "tree e3a1035abd2b319bb01e57d69b0ba6cab289297e\n"
506 + "parent 54e895b87c0768d2317a2b17062e3ad9f76a8105\n"
507 + "committer A U Thor <author@xample.com 1528968566 +0200\n"
508 + "gpgsig -----BEGIN PGP SIGNATURE-----\n" + " \n"
509 + " wsBcBAABCAAQBQJbGB4pCRBK7hj4Ov3rIwAAdHIIAENrvz23867ZgqrmyPemBEZP\n"
510 + " U24B1Tlq/DWvce2buaxmbNQngKZ0pv2s8VMc11916WfTIC9EKvioatmpjduWvhqj\n"
511 + " znQTFyiMor30pyYsfrqFuQZvqBW01o8GEWqLg8zjf9Rf0R3LlOEw86aT8CdHRlm6\n"
512 + " wlb22xb8qoX4RB+LYfz7MhK5F+yLOPXZdJnAVbuyoMGRnDpwdzjL5Hj671+XJxN5\n"
513 + " SasRdhxkkfw/ZnHxaKEc4juMz8Nziz27elRwhOQqlTYoXNJnsV//wy5Losd7aKi1\n"
514 + " xXXyUpndEOmT0CIcKHrN/kbYoVL28OJaxoBuva3WYQaRrzEe3X02NMxZe9gkSqA=\n"
515 + " =TClh\n" + " -----END PGP SIGNATURE-----\n"
516 + "some other header\n\n" + "commit message";
517
518 final RevCommit c;
519 c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
520 try (RevWalk rw = new RevWalk(db)) {
521 c.parseCanonical(rw, commit.getBytes(UTF_8));
522 }
523 String gpgSig = new String(c.getRawGpgSignature(), UTF_8);
524 assertTrue(gpgSig.startsWith("-----BEGIN"));
525 assertTrue(gpgSig.endsWith("END PGP SIGNATURE-----"));
526 }
527
528 @Test
529 public void testParse_NoGpgSig() throws Exception {
530 final RevCommit c = create("a message");
531 assertNull(c.getRawGpgSignature());
532 }
533 }