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