View Javadoc
1   /*
2    * Copyright (C) 2008-2009, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.revwalk;
45  
46  import static org.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertNotNull;
48  import static org.junit.Assert.assertNull;
49  import static org.junit.Assert.assertSame;
50  
51  import java.io.ByteArrayOutputStream;
52  import java.io.UnsupportedEncodingException;
53  import java.util.TimeZone;
54  
55  import org.eclipse.jgit.junit.RepositoryTestCase;
56  import org.eclipse.jgit.lib.CommitBuilder;
57  import org.eclipse.jgit.lib.Constants;
58  import org.eclipse.jgit.lib.ObjectId;
59  import org.eclipse.jgit.lib.ObjectInserter;
60  import org.eclipse.jgit.lib.PersonIdent;
61  import org.junit.Test;
62  
63  public class RevCommitParseTest extends RepositoryTestCase {
64  	@Test
65  	public void testParse_NoParents() throws Exception {
66  		final ObjectId treeId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
67  		final String authorName = "A U. Thor";
68  		final String authorEmail = "a_u_thor@example.com";
69  		final int authorTime = 1218123387;
70  		final String authorTimeZone = "+0700";
71  
72  		final String committerName = "C O. Miter";
73  		final String committerEmail = "comiter@example.com";
74  		final int committerTime = 1218123390;
75  		final String committerTimeZone = "-0500";
76  		final StringBuilder body = new StringBuilder();
77  
78  		body.append("tree ");
79  		body.append(treeId.name());
80  		body.append("\n");
81  
82  		body.append("author ");
83  		body.append(authorName);
84  		body.append(" <");
85  		body.append(authorEmail);
86  		body.append("> ");
87  		body.append(authorTime);
88  		body.append(" ");
89  		body.append(authorTimeZone);
90  		body.append(" \n");
91  
92  		body.append("committer ");
93  		body.append(committerName);
94  		body.append(" <");
95  		body.append(committerEmail);
96  		body.append("> ");
97  		body.append(committerTime);
98  		body.append(" ");
99  		body.append(committerTimeZone);
100 		body.append("\n");
101 
102 		body.append("\n");
103 
104 		final RevWalk rw = new RevWalk(db);
105 		final RevCommit c;
106 
107 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
108 		assertNull(c.getTree());
109 		assertNull(c.parents);
110 
111 		c.parseCanonical(rw, body.toString().getBytes("UTF-8"));
112 		assertNotNull(c.getTree());
113 		assertEquals(treeId, c.getTree().getId());
114 		assertSame(rw.lookupTree(treeId), c.getTree());
115 
116 		assertNotNull(c.parents);
117 		assertEquals(0, c.parents.length);
118 		assertEquals("", c.getFullMessage());
119 
120 		final PersonIdent cAuthor = c.getAuthorIdent();
121 		assertNotNull(cAuthor);
122 		assertEquals(authorName, cAuthor.getName());
123 		assertEquals(authorEmail, cAuthor.getEmailAddress());
124 		assertEquals((long)authorTime * 1000, cAuthor.getWhen().getTime());
125 		assertEquals(TimeZone.getTimeZone("GMT" + authorTimeZone), cAuthor.getTimeZone());
126 
127 		final PersonIdent cCommitter = c.getCommitterIdent();
128 		assertNotNull(cCommitter);
129 		assertEquals(committerName, cCommitter.getName());
130 		assertEquals(committerEmail, cCommitter.getEmailAddress());
131 		assertEquals((long)committerTime * 1000, cCommitter.getWhen().getTime());
132 		assertEquals(TimeZone.getTimeZone("GMT" + committerTimeZone), cCommitter.getTimeZone());
133 	}
134 
135 	private RevCommit create(final String msg) throws Exception {
136 		final StringBuilder b = new StringBuilder();
137 		b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
138 		b.append("author A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
139 		b.append("committer C O. Miter <c@example.com> 1218123390 -0500\n");
140 		b.append("\n");
141 		b.append(msg);
142 
143 		final RevCommit c;
144 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
145 		c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
146 		return c;
147 	}
148 
149 	@Test
150 	public void testParse_WeirdHeaderOnlyCommit() throws Exception {
151 		final StringBuilder b = new StringBuilder();
152 		b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
153 		b.append("author A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
154 		b.append("committer C O. Miter <c@example.com> 1218123390 -0500\n");
155 
156 		final RevCommit c;
157 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
158 		c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
159 
160 		assertEquals("", c.getFullMessage());
161 		assertEquals("", c.getShortMessage());
162 	}
163 
164 	@Test
165 	public void testParse_incompleteAuthorAndCommitter() throws Exception {
166 		final StringBuilder b = new StringBuilder();
167 		b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
168 		b.append("author <a_u_thor@example.com> 1218123387 +0700\n");
169 		b.append("committer <> 1218123390 -0500\n");
170 
171 		final RevCommit c;
172 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
173 		c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
174 
175 		assertEquals(new PersonIdent("", "a_u_thor@example.com", 1218123387000l, 7), c.getAuthorIdent());
176 		assertEquals(new PersonIdent("", "", 1218123390000l, -5), c.getCommitterIdent());
177 	}
178 
179 	@Test
180 	public void testParse_implicit_UTF8_encoded() throws Exception {
181 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
182 		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
183 		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("UTF-8"));
184 		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
185 		b.write("\n".getBytes("UTF-8"));
186 		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
187 		b.write("\n".getBytes("UTF-8"));
188 		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
189 		final RevCommit c;
190 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
191 		c.parseCanonical(new RevWalk(db), b.toByteArray());
192 
193 		assertSame(Constants.CHARSET, c.getEncoding());
194 		assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
195 		assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
196 		assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c.getFullMessage());
197 	}
198 
199 	@Test
200 	public void testParse_implicit_mixed_encoded() throws Exception {
201 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
202 		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
203 		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("ISO-8859-1"));
204 		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
205 		b.write("\n".getBytes("UTF-8"));
206 		b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
207 		b.write("\n".getBytes("UTF-8"));
208 		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
209 		final RevCommit c;
210 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
211 		c.parseCanonical(new RevWalk(db), b.toByteArray());
212 
213 		assertSame(Constants.CHARSET, c.getEncoding());
214 		assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
215 		assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
216 		assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c.getFullMessage());
217 	}
218 
219 	/**
220 	 * Test parsing of a commit whose encoding is given and works.
221 	 *
222 	 * @throws Exception
223 	 */
224 	@Test
225 	public void testParse_explicit_encoded() throws Exception {
226 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
227 		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("EUC-JP"));
228 		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("EUC-JP"));
229 		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("EUC-JP"));
230 		b.write("encoding euc_JP\n".getBytes("EUC-JP"));
231 		b.write("\n".getBytes("EUC-JP"));
232 		b.write("\u304d\u308c\u3044\n".getBytes("EUC-JP"));
233 		b.write("\n".getBytes("EUC-JP"));
234 		b.write("Hi\n".getBytes("EUC-JP"));
235 		final RevCommit c;
236 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
237 		c.parseCanonical(new RevWalk(db), b.toByteArray());
238 
239 		assertEquals("EUC-JP", c.getEncoding().name());
240 		assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
241 		assertEquals("\u304d\u308c\u3044", c.getShortMessage());
242 		assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
243 	}
244 
245 	/**
246 	 * This is a twisted case, but show what we expect here. We can revise the
247 	 * expectations provided this case is updated.
248 	 *
249 	 * What happens here is that an encoding us given, but data is not encoded
250 	 * that way (and we can detect it), so we try other encodings.
251 	 *
252 	 * @throws Exception
253 	 */
254 	@Test
255 	public void testParse_explicit_bad_encoded() throws Exception {
256 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
257 		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
258 		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("ISO-8859-1"));
259 		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
260 		b.write("encoding EUC-JP\n".getBytes("UTF-8"));
261 		b.write("\n".getBytes("UTF-8"));
262 		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
263 		b.write("\n".getBytes("UTF-8"));
264 		b.write("Hi\n".getBytes("UTF-8"));
265 		final RevCommit c;
266 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
267 		c.parseCanonical(new RevWalk(db), b.toByteArray());
268 
269 		assertEquals("EUC-JP", c.getEncoding().name());
270 		assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
271 		assertEquals("\u304d\u308c\u3044", c.getShortMessage());
272 		assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
273 	}
274 
275 	/**
276 	 * This is a twisted case too, but show what we expect here. We can revise the
277 	 * expectations provided this case is updated.
278 	 *
279 	 * What happens here is that an encoding us given, but data is not encoded
280 	 * that way (and we can detect it), so we try other encodings. Here data could
281 	 * actually be decoded in the stated encoding, but we override using UTF-8.
282 	 *
283 	 * @throws Exception
284 	 */
285 	@Test
286 	public void testParse_explicit_bad_encoded2() throws Exception {
287 		final ByteArrayOutputStream b = new ByteArrayOutputStream();
288 		b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
289 		b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("UTF-8"));
290 		b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
291 		b.write("encoding ISO-8859-1\n".getBytes("UTF-8"));
292 		b.write("\n".getBytes("UTF-8"));
293 		b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
294 		b.write("\n".getBytes("UTF-8"));
295 		b.write("Hi\n".getBytes("UTF-8"));
296 		final RevCommit c;
297 		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
298 		c.parseCanonical(new RevWalk(db), b.toByteArray());
299 
300 		assertEquals("ISO-8859-1", c.getEncoding().name());
301 		assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
302 		assertEquals("\u304d\u308c\u3044", c.getShortMessage());
303 		assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
304 	}
305 
306 	@Test
307 	public void testParse_NoMessage() throws Exception {
308 		final String msg = "";
309 		final RevCommit c = create(msg);
310 		assertEquals(msg, c.getFullMessage());
311 		assertEquals(msg, c.getShortMessage());
312 	}
313 
314 	@Test
315 	public void testParse_OnlyLFMessage() throws Exception {
316 		final RevCommit c = create("\n");
317 		assertEquals("\n", c.getFullMessage());
318 		assertEquals("", c.getShortMessage());
319 	}
320 
321 	@Test
322 	public void testParse_ShortLineOnlyNoLF() throws Exception {
323 		final String shortMsg = "This is a short message.";
324 		final RevCommit c = create(shortMsg);
325 		assertEquals(shortMsg, c.getFullMessage());
326 		assertEquals(shortMsg, c.getShortMessage());
327 	}
328 
329 	@Test
330 	public void testParse_ShortLineOnlyEndLF() throws Exception {
331 		final String shortMsg = "This is a short message.";
332 		final String fullMsg = shortMsg + "\n";
333 		final RevCommit c = create(fullMsg);
334 		assertEquals(fullMsg, c.getFullMessage());
335 		assertEquals(shortMsg, c.getShortMessage());
336 	}
337 
338 	@Test
339 	public void testParse_ShortLineOnlyEmbeddedLF() throws Exception {
340 		final String fullMsg = "This is a\nshort message.";
341 		final String shortMsg = fullMsg.replace('\n', ' ');
342 		final RevCommit c = create(fullMsg);
343 		assertEquals(fullMsg, c.getFullMessage());
344 		assertEquals(shortMsg, c.getShortMessage());
345 	}
346 
347 	@Test
348 	public void testParse_ShortLineOnlyEmbeddedAndEndingLF() throws Exception {
349 		final String fullMsg = "This is a\nshort message.\n";
350 		final String shortMsg = "This is a short message.";
351 		final RevCommit c = create(fullMsg);
352 		assertEquals(fullMsg, c.getFullMessage());
353 		assertEquals(shortMsg, c.getShortMessage());
354 	}
355 
356 	@Test
357 	public void testParse_GitStyleMessage() throws Exception {
358 		final String shortMsg = "This fixes a bug.";
359 		final String body = "We do it with magic and pixie dust and stuff.\n"
360 				+ "\n" + "Signed-off-by: A U. Thor <author@example.com>\n";
361 		final String fullMsg = shortMsg + "\n" + "\n" + body;
362 		final RevCommit c = create(fullMsg);
363 		assertEquals(fullMsg, c.getFullMessage());
364 		assertEquals(shortMsg, c.getShortMessage());
365 	}
366 
367 	@Test
368 	public void testParse_PublicParseMethod()
369 			throws UnsupportedEncodingException {
370 		ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
371 		CommitBuilder src = new CommitBuilder();
372 		src.setTreeId(fmt.idFor(Constants.OBJ_TREE, new byte[] {}));
373 		src.setAuthor(author);
374 		src.setCommitter(committer);
375 		src.setMessage("Test commit\n\nThis is a test.\n");
376 
377 		RevCommit p = RevCommit.parse(src.build());
378 		assertEquals(src.getTreeId(), p.getTree());
379 		assertEquals(0, p.getParentCount());
380 		assertEquals(author, p.getAuthorIdent());
381 		assertEquals(committer, p.getCommitterIdent());
382 		assertEquals("Test commit", p.getShortMessage());
383 		assertEquals(src.getMessage(), p.getFullMessage());
384 	}
385 
386 	@Test
387 	public void testParse_GitStyleMessageWithCRLF() throws Exception {
388 		final String shortMsgIn = "This fixes a\r\nbug.\r\n\r\n";
389 		final String shortMsg = "This fixes a bug.";
390 		final String body = "We do it with magic and pixie dust\r\nand stuff.\r\n"
391 				+ "\r\n\r\n"
392 				+ "Signed-off-by: A U. Thor <author@example.com>\r\n";
393 		final String fullMsg = shortMsgIn + "\r\n" + "\r\n" + body;
394 		final RevCommit c = create(fullMsg);
395 		assertEquals(fullMsg, c.getFullMessage());
396 		assertEquals(shortMsg, c.getShortMessage());
397 	}
398 
399 	private static ObjectId id(final String str) {
400 		return ObjectId.fromString(str);
401 	}
402 }