View Javadoc
1   /*
2    * Copyright (C) 2008, 2020, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
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.US_ASCII;
15  import static java.nio.charset.StandardCharsets.UTF_8;
16  import static org.junit.Assert.assertEquals;
17  import static org.junit.Assert.assertNotNull;
18  import static org.junit.Assert.assertNull;
19  import static org.junit.Assert.assertSame;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.UnsupportedEncodingException;
23  
24  import org.eclipse.jgit.errors.CorruptObjectException;
25  import org.eclipse.jgit.junit.RepositoryTestCase;
26  import org.eclipse.jgit.lib.Constants;
27  import org.eclipse.jgit.lib.ObjectId;
28  import org.eclipse.jgit.lib.ObjectInserter;
29  import org.eclipse.jgit.lib.PersonIdent;
30  import org.eclipse.jgit.lib.TagBuilder;
31  import org.junit.Test;
32  
33  public class RevTagParseTest extends RepositoryTestCase {
34  	@Test
35  	public void testTagBlob() throws Exception {
36  		testOneType(Constants.OBJ_BLOB);
37  	}
38  
39  	@Test
40  	public void testTagTree() throws Exception {
41  		testOneType(Constants.OBJ_TREE);
42  	}
43  
44  	@Test
45  	public void testTagCommit() throws Exception {
46  		testOneType(Constants.OBJ_COMMIT);
47  	}
48  
49  	@Test
50  	public void testTagTag() throws Exception {
51  		testOneType(Constants.OBJ_TAG);
52  	}
53  
54  	private void testOneType(int typeCode) throws Exception {
55  		final ObjectId id = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
56  		final StringBuilder b = new StringBuilder();
57  		b.append("object " + id.name() + "\n");
58  		b.append("type " + Constants.typeString(typeCode) + "\n");
59  		b.append("tag v1.2.3.4.5\n");
60  		b.append("tagger A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
61  		b.append("\n");
62  
63  		final RevTag c;
64  
65  		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
66  		assertNull(c.getObject());
67  		assertNull(c.getTagName());
68  
69  		try (RevWalk rw = new RevWalk(db)) {
70  			c.parseCanonical(rw, b.toString().getBytes(UTF_8));
71  			assertNotNull(c.getObject());
72  			assertEquals(id, c.getObject().getId());
73  			assertSame(rw.lookupAny(id, typeCode), c.getObject());
74  		}
75  	}
76  
77  	@Test
78  	public void testParseAllFields() throws Exception {
79  		final ObjectId treeId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
80  		final String name = "v1.2.3.4.5";
81  		final String taggerName = "A U. Thor";
82  		final String taggerEmail = "a_u_thor@example.com";
83  		final int taggerTime = 1218123387;
84  
85  		final StringBuilder body = new StringBuilder();
86  
87  		body.append("object ");
88  		body.append(treeId.name());
89  		body.append("\n");
90  
91  		body.append("type tree\n");
92  
93  		body.append("tag ");
94  		body.append(name);
95  		body.append("\n");
96  
97  		body.append("tagger ");
98  		body.append(taggerName);
99  		body.append(" <");
100 		body.append(taggerEmail);
101 		body.append("> ");
102 		body.append(taggerTime);
103 		body.append(" +0700\n");
104 
105 		body.append("\n");
106 
107 		final RevTag c;
108 
109 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
110 		assertNull(c.getObject());
111 		assertNull(c.getTagName());
112 
113 		try (RevWalk rw = new RevWalk(db)) {
114 			c.parseCanonical(rw, body.toString().getBytes(UTF_8));
115 			assertNotNull(c.getObject());
116 			assertEquals(treeId, c.getObject().getId());
117 			assertSame(rw.lookupTree(treeId), c.getObject());
118 		}
119 		assertNotNull(c.getTagName());
120 		assertEquals(name, c.getTagName());
121 		assertEquals("", c.getFullMessage());
122 		assertNull(c.getRawGpgSignature());
123 
124 		final PersonIdent cTagger = c.getTaggerIdent();
125 		assertNotNull(cTagger);
126 		assertEquals(taggerName, cTagger.getName());
127 		assertEquals(taggerEmail, cTagger.getEmailAddress());
128 	}
129 
130 	@Test
131 	public void testParseOldStyleNoTagger() throws Exception {
132 		final ObjectId treeId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
133 		final String name = "v1.2.3.4.5";
134 		final String fakeSignature = "-----BEGIN PGP SIGNATURE-----\n" //
135 				+ "Version: GnuPG v1.4.1 (GNU/Linux)\n" //
136 				+ "\n" //
137 				+ "iD8DBQBC0b9oF3Y\n" //
138 				+ "-----END PGP SIGNATURE-----";
139 		final String message = "test\n" + fakeSignature + '\n';
140 
141 		final StringBuilder body = new StringBuilder();
142 
143 		body.append("object ");
144 		body.append(treeId.name());
145 		body.append("\n");
146 
147 		body.append("type tree\n");
148 
149 		body.append("tag ");
150 		body.append(name);
151 		body.append("\n");
152 		body.append("\n");
153 		body.append(message);
154 
155 		final RevTag c;
156 
157 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
158 		assertNull(c.getObject());
159 		assertNull(c.getTagName());
160 
161 		try (RevWalk rw = new RevWalk(db)) {
162 			c.parseCanonical(rw, body.toString().getBytes(UTF_8));
163 			assertNotNull(c.getObject());
164 			assertEquals(treeId, c.getObject().getId());
165 			assertSame(rw.lookupTree(treeId), c.getObject());
166 		}
167 
168 		assertNotNull(c.getTagName());
169 		assertEquals(name, c.getTagName());
170 		assertEquals("test", c.getShortMessage());
171 		assertEquals("test\n", c.getFullMessage());
172 		assertEquals(fakeSignature + '\n',
173 				new String(c.getRawGpgSignature(), US_ASCII));
174 
175 		assertNull(c.getTaggerIdent());
176 	}
177 
178 	private RevTag create(String msg) throws Exception {
179 		final StringBuilder b = new StringBuilder();
180 		b.append("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
181 		b.append("type tree\n");
182 		b.append("tag v1.2.3.4.5\n");
183 		b.append("tagger A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
184 		b.append("\n");
185 		b.append(msg);
186 
187 		final RevTag c;
188 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
189 		try (RevWalk rw = new RevWalk(db)) {
190 			c.parseCanonical(rw, b.toString().getBytes(UTF_8));
191 		}
192 		return c;
193 	}
194 
195 	@Test
196 	public void testParse_implicit_UTF8_encoded() throws Exception {
197 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
198 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
199 				.getBytes(UTF_8));
200 		b.write("type tree\n".getBytes(UTF_8));
201 		b.write("tag v1.2.3.4.5\n".getBytes(UTF_8));
202 
203 		b
204 				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
205 						.getBytes(UTF_8));
206 		b.write("\n".getBytes(UTF_8));
207 		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8));
208 		b.write("\n".getBytes(UTF_8));
209 		b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
210 		final RevTag c;
211 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
212 		try (RevWalk rw = new RevWalk(db)) {
213 			c.parseCanonical(rw, b.toByteArray());
214 		}
215 
216 		assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
217 		assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
218 		assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c
219 				.getFullMessage());
220 	}
221 
222 	@Test
223 	public void testParse_implicit_mixed_encoded() throws Exception {
224 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
225 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
226 				.getBytes(UTF_8));
227 		b.write("type tree\n".getBytes(UTF_8));
228 		b.write("tag v1.2.3.4.5\n".getBytes(UTF_8));
229 		b.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
230 				.getBytes(ISO_8859_1));
231 		b.write("\n".getBytes(UTF_8));
232 		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8));
233 		b.write("\n".getBytes(UTF_8));
234 		b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
235 		final RevTag c;
236 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
237 		try (RevWalk rw = new RevWalk(db)) {
238 			c.parseCanonical(rw, b.toByteArray());
239 		}
240 
241 		assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
242 		assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
243 		assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c
244 				.getFullMessage());
245 	}
246 
247 	/**
248 	 * Test parsing of a commit whose encoding is given and works.
249 	 *
250 	 * @throws Exception
251 	 */
252 	@Test
253 	public void testParse_explicit_encoded() throws Exception {
254 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
255 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
256 				.getBytes("EUC-JP"));
257 		b.write("type tree\n".getBytes("EUC-JP"));
258 		b.write("tag v1.2.3.4.5\n".getBytes("EUC-JP"));
259 		b
260 				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
261 						.getBytes("EUC-JP"));
262 		b.write("encoding euc_JP\n".getBytes("EUC-JP"));
263 		b.write("\n".getBytes("EUC-JP"));
264 		b.write("\u304d\u308c\u3044\n".getBytes("EUC-JP"));
265 		b.write("\n".getBytes("EUC-JP"));
266 		b.write("Hi\n".getBytes("EUC-JP"));
267 		final RevTag c;
268 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
269 		try (RevWalk rw = new RevWalk(db)) {
270 			c.parseCanonical(rw, b.toByteArray());
271 		}
272 
273 		assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
274 		assertEquals("\u304d\u308c\u3044", c.getShortMessage());
275 		assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
276 	}
277 
278 	/**
279 	 * This is a twisted case, but show what we expect here. We can revise the
280 	 * expectations provided this case is updated.
281 	 *
282 	 * What happens here is that an encoding us given, but data is not encoded
283 	 * that way (and we can detect it), so we try other encodings.
284 	 *
285 	 * @throws Exception
286 	 */
287 	@Test
288 	public void testParse_explicit_bad_encoded() throws Exception {
289 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
290 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
291 				.getBytes(UTF_8));
292 		b.write("type tree\n".getBytes(UTF_8));
293 		b.write("tag v1.2.3.4.5\n".getBytes(UTF_8));
294 		b
295 				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
296 						.getBytes(ISO_8859_1));
297 		b.write("encoding EUC-JP\n".getBytes(UTF_8));
298 		b.write("\n".getBytes(UTF_8));
299 		b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
300 		b.write("\n".getBytes(UTF_8));
301 		b.write("Hi\n".getBytes(UTF_8));
302 		final RevTag c;
303 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
304 		try (RevWalk rw = new RevWalk(db)) {
305 			c.parseCanonical(rw, b.toByteArray());
306 		}
307 
308 		assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
309 		assertEquals("\u304d\u308c\u3044", c.getShortMessage());
310 		assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
311 	}
312 
313 	/**
314 	 * This is a twisted case too, but show what we expect here. We can revise
315 	 * the expectations provided this case is updated.
316 	 *
317 	 * What happens here is that an encoding us given, but data is not encoded
318 	 * that way (and we can detect it), so we try other encodings. Here data
319 	 * could actually be decoded in the stated encoding, but we override using
320 	 * UTF-8.
321 	 *
322 	 * @throws Exception
323 	 */
324 	@Test
325 	public void testParse_explicit_bad_encoded2() throws Exception {
326 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
327 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
328 				.getBytes(UTF_8));
329 		b.write("type tree\n".getBytes(UTF_8));
330 		b.write("tag v1.2.3.4.5\n".getBytes(UTF_8));
331 		b
332 				.write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
333 						.getBytes(UTF_8));
334 		b.write("encoding ISO-8859-1\n".getBytes(UTF_8));
335 		b.write("\n".getBytes(UTF_8));
336 		b.write("\u304d\u308c\u3044\n".getBytes(UTF_8));
337 		b.write("\n".getBytes(UTF_8));
338 		b.write("Hi\n".getBytes(UTF_8));
339 		final RevTag c;
340 		c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
341 		try (RevWalk rw = new RevWalk(db)) {
342 			c.parseCanonical(rw, b.toByteArray());
343 		}
344 
345 		assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
346 		assertEquals("\u304d\u308c\u3044", c.getShortMessage());
347 		assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
348 	}
349 
350 	@Test
351 	public void testParse_illegalEncoding() throws Exception {
352 		ByteArrayOutputStream b = new ByteArrayOutputStream();
353 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
354 		b.write("type tree\n".getBytes(UTF_8));
355 		b.write("tag v1.0\n".getBytes(UTF_8));
356 		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
357 		b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8));
358 		b.write("\n".getBytes(UTF_8));
359 		b.write("message\n".getBytes(UTF_8));
360 
361 		RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
362 		try (RevWalk rw = new RevWalk(db)) {
363 			t.parseCanonical(rw, b.toByteArray());
364 		}
365 
366 		assertEquals("t", t.getTaggerIdent().getName());
367 		assertEquals("message", t.getShortMessage());
368 		assertEquals("message\n", t.getFullMessage());
369 	}
370 
371 	@Test
372 	public void testParse_unsupportedEncoding() throws Exception {
373 		ByteArrayOutputStream b = new ByteArrayOutputStream();
374 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8));
375 		b.write("type tree\n".getBytes(UTF_8));
376 		b.write("tag v1.0\n".getBytes(UTF_8));
377 		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
378 		b.write("encoding it_IT.UTF8\n".getBytes(UTF_8));
379 		b.write("\n".getBytes(UTF_8));
380 		b.write("message\n".getBytes(UTF_8));
381 
382 		RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
383 		try (RevWalk rw = new RevWalk(db)) {
384 			t.parseCanonical(rw, b.toByteArray());
385 		}
386 
387 		assertEquals("t", t.getTaggerIdent().getName());
388 		assertEquals("message", t.getShortMessage());
389 		assertEquals("message\n", t.getFullMessage());
390 	}
391 
392 	@Test
393 	public void testParse_gpgSignature() throws Exception {
394 		final String signature = "-----BEGIN PGP SIGNATURE-----\n\n"
395 				+ "wsBcBAABCAAQBQJbGB4pCRBK7hj4Ov3rIwAAdHIIAENrvz23867ZgqrmyPemBEZP\n"
396 				+ "U24B1Tlq/DWvce2buaxmbNQngKZ0pv2s8VMc11916WfTIC9EKvioatmpjduWvhqj\n"
397 				+ "znQTFyiMor30pyYsfrqFuQZvqBW01o8GEWqLg8zjf9Rf0R3LlOEw86aT8CdHRlm6\n"
398 				+ "wlb22xb8qoX4RB+LYfz7MhK5F+yLOPXZdJnAVbuyoMGRnDpwdzjL5Hj671+XJxN5\n"
399 				+ "SasRdhxkkfw/ZnHxaKEc4juMz8Nziz27elRwhOQqlTYoXNJnsV//wy5Losd7aKi1\n"
400 				+ "xXXyUpndEOmT0CIcKHrN/kbYoVL28OJaxoBuva3WYQaRrzEe3X02NMxZe9gkSqA=\n"
401 				+ "=TClh\n" + "-----END PGP SIGNATURE-----";
402 		ByteArrayOutputStream b = new ByteArrayOutputStream();
403 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
404 				.getBytes(UTF_8));
405 		b.write("type tree\n".getBytes(UTF_8));
406 		b.write("tag v1.0\n".getBytes(UTF_8));
407 		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
408 		b.write('\n');
409 		b.write("message\n".getBytes(UTF_8));
410 		b.write(signature.getBytes(US_ASCII));
411 		b.write('\n');
412 
413 		RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
414 		try (RevWalk rw = new RevWalk(db)) {
415 			t.parseCanonical(rw, b.toByteArray());
416 		}
417 
418 		assertEquals("t", t.getTaggerIdent().getName());
419 		assertEquals("message", t.getShortMessage());
420 		assertEquals("message\n", t.getFullMessage());
421 		String gpgSig = new String(t.getRawGpgSignature(), UTF_8);
422 		assertEquals(signature + '\n', gpgSig);
423 	}
424 
425 	@Test
426 	public void testParse_gpgSignature2() throws Exception {
427 		final String signature = "-----BEGIN PGP SIGNATURE-----\n\n"
428 				+ "wsBcBAABCAAQBQJbGB4pCRBK7hj4Ov3rIwAAdHIIAENrvz23867ZgqrmyPemBEZP\n"
429 				+ "U24B1Tlq/DWvce2buaxmbNQngKZ0pv2s8VMc11916WfTIC9EKvioatmpjduWvhqj\n"
430 				+ "znQTFyiMor30pyYsfrqFuQZvqBW01o8GEWqLg8zjf9Rf0R3LlOEw86aT8CdHRlm6\n"
431 				+ "wlb22xb8qoX4RB+LYfz7MhK5F+yLOPXZdJnAVbuyoMGRnDpwdzjL5Hj671+XJxN5\n"
432 				+ "SasRdhxkkfw/ZnHxaKEc4juMz8Nziz27elRwhOQqlTYoXNJnsV//wy5Losd7aKi1\n"
433 				+ "xXXyUpndEOmT0CIcKHrN/kbYoVL28OJaxoBuva3WYQaRrzEe3X02NMxZe9gkSqA=\n"
434 				+ "=TClh\n" + "-----END PGP SIGNATURE-----";
435 		ByteArrayOutputStream b = new ByteArrayOutputStream();
436 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
437 				.getBytes(UTF_8));
438 		b.write("type tree\n".getBytes(UTF_8));
439 		b.write("tag v1.0\n".getBytes(UTF_8));
440 		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
441 		b.write('\n');
442 		String message = "message\n\n" + signature.replace("xXXy", "aAAb")
443 				+ '\n';
444 		b.write(message.getBytes(UTF_8));
445 		b.write(signature.getBytes(US_ASCII));
446 		b.write('\n');
447 
448 		RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
449 		try (RevWalk rw = new RevWalk(db)) {
450 			t.parseCanonical(rw, b.toByteArray());
451 		}
452 
453 		assertEquals("t", t.getTaggerIdent().getName());
454 		assertEquals("message", t.getShortMessage());
455 		assertEquals(message, t.getFullMessage());
456 		String gpgSig = new String(t.getRawGpgSignature(), UTF_8);
457 		assertEquals(signature + '\n', gpgSig);
458 	}
459 
460 	@Test
461 	public void testParse_gpgSignature3() throws Exception {
462 		final String signature = "-----BEGIN PGP SIGNATURE-----\n\n"
463 				+ "wsBcBAABCAAQBQJbGB4pCRBK7hj4Ov3rIwAAdHIIAENrvz23867ZgqrmyPemBEZP\n"
464 				+ "U24B1Tlq/DWvce2buaxmbNQngKZ0pv2s8VMc11916WfTIC9EKvioatmpjduWvhqj\n"
465 				+ "znQTFyiMor30pyYsfrqFuQZvqBW01o8GEWqLg8zjf9Rf0R3LlOEw86aT8CdHRlm6\n"
466 				+ "wlb22xb8qoX4RB+LYfz7MhK5F+yLOPXZdJnAVbuyoMGRnDpwdzjL5Hj671+XJxN5\n"
467 				+ "SasRdhxkkfw/ZnHxaKEc4juMz8Nziz27elRwhOQqlTYoXNJnsV//wy5Losd7aKi1\n"
468 				+ "xXXyUpndEOmT0CIcKHrN/kbYoVL28OJaxoBuva3WYQaRrzEe3X02NMxZe9gkSqA=\n"
469 				+ "=TClh\n" + "-----END PGP SIGNATURE-----";
470 		ByteArrayOutputStream b = new ByteArrayOutputStream();
471 		b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
472 				.getBytes(UTF_8));
473 		b.write("type tree\n".getBytes(UTF_8));
474 		b.write("tag v1.0\n".getBytes(UTF_8));
475 		b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8));
476 		b.write('\n');
477 		String message = "message\n\n-----BEGIN PGP SIGNATURE-----\n";
478 		b.write(message.getBytes(UTF_8));
479 		b.write(signature.getBytes(US_ASCII));
480 		b.write('\n');
481 
482 		RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
483 		try (RevWalk rw = new RevWalk(db)) {
484 			t.parseCanonical(rw, b.toByteArray());
485 		}
486 
487 		assertEquals("t", t.getTaggerIdent().getName());
488 		assertEquals("message", t.getShortMessage());
489 		assertEquals(message, t.getFullMessage());
490 		String gpgSig = new String(t.getRawGpgSignature(), UTF_8);
491 		assertEquals(signature + '\n', gpgSig);
492 	}
493 
494 	@Test
495 	public void testParse_NoMessage() throws Exception {
496 		final String msg = "";
497 		final RevTag c = create(msg);
498 		assertEquals(msg, c.getFullMessage());
499 		assertEquals(msg, c.getShortMessage());
500 	}
501 
502 	@Test
503 	public void testParse_OnlyLFMessage() throws Exception {
504 		final RevTag c = create("\n");
505 		assertEquals("\n", c.getFullMessage());
506 		assertEquals("", c.getShortMessage());
507 	}
508 
509 	@Test
510 	public void testParse_ShortLineOnlyNoLF() throws Exception {
511 		final String shortMsg = "This is a short message.";
512 		final RevTag c = create(shortMsg);
513 		assertEquals(shortMsg, c.getFullMessage());
514 		assertEquals(shortMsg, c.getShortMessage());
515 	}
516 
517 	@Test
518 	public void testParse_ShortLineOnlyEndLF() throws Exception {
519 		final String shortMsg = "This is a short message.";
520 		final String fullMsg = shortMsg + "\n";
521 		final RevTag c = create(fullMsg);
522 		assertEquals(fullMsg, c.getFullMessage());
523 		assertEquals(shortMsg, c.getShortMessage());
524 	}
525 
526 	@Test
527 	public void testParse_ShortLineOnlyEmbeddedLF() throws Exception {
528 		final String fullMsg = "This is a\nshort message.";
529 		final String shortMsg = fullMsg.replace('\n', ' ');
530 		final RevTag c = create(fullMsg);
531 		assertEquals(fullMsg, c.getFullMessage());
532 		assertEquals(shortMsg, c.getShortMessage());
533 	}
534 
535 	@Test
536 	public void testParse_ShortLineOnlyEmbeddedAndEndingLF() throws Exception {
537 		final String fullMsg = "This is a\nshort message.\n";
538 		final String shortMsg = "This is a short message.";
539 		final RevTag c = create(fullMsg);
540 		assertEquals(fullMsg, c.getFullMessage());
541 		assertEquals(shortMsg, c.getShortMessage());
542 	}
543 
544 	@Test
545 	public void testParse_GitStyleMessage() throws Exception {
546 		final String shortMsg = "This fixes a bug.";
547 		final String body = "We do it with magic and pixie dust and stuff.\n"
548 				+ "\n" + "Signed-off-by: A U. Thor <author@example.com>\n";
549 		final String fullMsg = shortMsg + "\n" + "\n" + body;
550 		final RevTag c = create(fullMsg);
551 		assertEquals(fullMsg, c.getFullMessage());
552 		assertEquals(shortMsg, c.getShortMessage());
553 	}
554 
555 	@Test
556 	public void testParse_PublicParseMethod()
557 			throws CorruptObjectException, UnsupportedEncodingException {
558 		TagBuilder src = new TagBuilder();
559 		try (ObjectInserter.Formatter fmt = new ObjectInserter.Formatter()) {
560 			src.setObjectId(fmt.idFor(Constants.OBJ_TREE, new byte[] {}),
561 					Constants.OBJ_TREE);
562 		}
563 		src.setTagger(committer);
564 		src.setTag("a.test");
565 		src.setMessage("Test tag\n\nThis is a test.\n");
566 
567 		RevTag p = RevTag.parse(src.build());
568 		assertEquals(src.getObjectId(), p.getObject());
569 		assertEquals(committer, p.getTaggerIdent());
570 		assertEquals("a.test", p.getTagName());
571 		assertEquals("Test tag", p.getShortMessage());
572 		assertEquals(src.getMessage(), p.getFullMessage());
573 	}
574 
575 	private static ObjectId id(String str) {
576 		return ObjectId.fromString(str);
577 	}
578 }