View Javadoc
1   /*
2    * Copyright (C) 2015, 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.junit;
45  
46  import static java.nio.charset.StandardCharsets.UTF_8;
47  import static org.junit.Assert.assertEquals;
48  import static org.junit.Assert.assertFalse;
49  import static org.junit.Assert.assertNotEquals;
50  import static org.junit.Assert.assertNull;
51  import static org.junit.Assert.assertSame;
52  import static org.junit.Assert.assertTrue;
53  
54  import java.util.Date;
55  import java.util.regex.Pattern;
56  
57  import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
58  import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
59  import org.eclipse.jgit.lib.AnyObjectId;
60  import org.eclipse.jgit.lib.Constants;
61  import org.eclipse.jgit.lib.ObjectId;
62  import org.eclipse.jgit.lib.ObjectLoader;
63  import org.eclipse.jgit.lib.PersonIdent;
64  import org.eclipse.jgit.lib.Ref;
65  import org.eclipse.jgit.revwalk.RevBlob;
66  import org.eclipse.jgit.revwalk.RevCommit;
67  import org.eclipse.jgit.revwalk.RevObject;
68  import org.eclipse.jgit.revwalk.RevWalk;
69  import org.eclipse.jgit.treewalk.TreeWalk;
70  import org.junit.After;
71  import org.junit.Before;
72  import org.junit.Test;
73  
74  public class TestRepositoryTest {
75  	private TestRepository<InMemoryRepository> tr;
76  	private InMemoryRepository repo;
77  	private RevWalk rw;
78  
79  	@Before
80  	public void setUp() throws Exception {
81  		tr = new TestRepository<>(new InMemoryRepository(
82  				new DfsRepositoryDescription("test")));
83  		repo = tr.getRepository();
84  		rw = tr.getRevWalk();
85  	}
86  
87  	@After
88  	public void tearDown() {
89  		rw.close();
90  		repo.close();
91  	}
92  
93  	@Test
94  	public void insertChangeId() throws Exception {
95  		RevCommit c1 = tr.commit().message("message").insertChangeId().create();
96  		rw.parseBody(c1);
97  		assertTrue(Pattern.matches(
98  				"^message\n\nChange-Id: I[0-9a-f]{40}\n$", c1.getFullMessage()));
99  
100 		RevCommit c2 = tr.commit().message("").insertChangeId().create();
101 		rw.parseBody(c2);
102 		assertEquals("\n\nChange-Id: I0000000000000000000000000000000000000000\n",
103 				c2.getFullMessage());
104 	}
105 
106 	@Test
107 	public void insertChangeIdIgnoresExisting() throws Exception {
108 		String msg = "message\n"
109 				+ "\n"
110 				+	"Change-Id: Ideadbeefdeadbeefdeadbeefdeadbeefdeadbeef\n";
111 		RevCommit c = tr.commit().message(msg).insertChangeId().create();
112 		rw.parseBody(c);
113 		assertEquals(msg, c.getFullMessage());
114 	}
115 
116 	@Test
117 	public void insertExplicitChangeId() throws Exception {
118 		RevCommit c = tr.commit().message("message")
119 				.insertChangeId("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
120 				.create();
121 		rw.parseBody(c);
122 		assertEquals("message\n\n"
123 				+ "Change-Id: Ideadbeefdeadbeefdeadbeefdeadbeefdeadbeef\n"
124 				, c.getFullMessage());
125 	}
126 
127 	@Test
128 	public void resetFromSymref() throws Exception {
129 		repo.updateRef("HEAD").link("refs/heads/master");
130 		Ref head = repo.exactRef("HEAD");
131 		RevCommit master = tr.branch("master").commit().create();
132 		RevCommit branch = tr.branch("branch").commit().create();
133 		RevCommit detached = tr.commit().create();
134 
135 		assertTrue(head.isSymbolic());
136 		assertEquals("refs/heads/master", head.getTarget().getName());
137 		assertEquals(master, repo.exactRef("refs/heads/master").getObjectId());
138 		assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId());
139 
140 		// Reset to branches preserves symref.
141 		tr.reset("master");
142 		head = repo.exactRef("HEAD");
143 		assertEquals(master, head.getObjectId());
144 		assertTrue(head.isSymbolic());
145 		assertEquals("refs/heads/master", head.getTarget().getName());
146 
147 		tr.reset("branch");
148 		head = repo.exactRef("HEAD");
149 		assertEquals(branch, head.getObjectId());
150 		assertTrue(head.isSymbolic());
151 		assertEquals("refs/heads/master", head.getTarget().getName());
152 		ObjectId lastHeadBeforeDetach = head.getObjectId().copy();
153 
154 		// Reset to a SHA-1 detaches.
155 		tr.reset(detached);
156 		head = repo.exactRef("HEAD");
157 		assertEquals(detached, head.getObjectId());
158 		assertFalse(head.isSymbolic());
159 
160 		tr.reset(detached.name());
161 		head = repo.exactRef("HEAD");
162 		assertEquals(detached, head.getObjectId());
163 		assertFalse(head.isSymbolic());
164 
165 		// Reset back to a branch remains detached.
166 		tr.reset("master");
167 		head = repo.exactRef("HEAD");
168 		assertEquals(lastHeadBeforeDetach, head.getObjectId());
169 		assertFalse(head.isSymbolic());
170 	}
171 
172 	@Test
173 	public void resetFromDetachedHead() throws Exception {
174 		Ref head = repo.exactRef("HEAD");
175 		RevCommit master = tr.branch("master").commit().create();
176 		RevCommit branch = tr.branch("branch").commit().create();
177 		RevCommit detached = tr.commit().create();
178 
179 		assertNull(head);
180 		assertEquals(master, repo.exactRef("refs/heads/master").getObjectId());
181 		assertEquals(branch, repo.exactRef("refs/heads/branch").getObjectId());
182 
183 		tr.reset("master");
184 		head = repo.exactRef("HEAD");
185 		assertEquals(master, head.getObjectId());
186 		assertFalse(head.isSymbolic());
187 
188 		tr.reset("branch");
189 		head = repo.exactRef("HEAD");
190 		assertEquals(branch, head.getObjectId());
191 		assertFalse(head.isSymbolic());
192 
193 		tr.reset(detached);
194 		head = repo.exactRef("HEAD");
195 		assertEquals(detached, head.getObjectId());
196 		assertFalse(head.isSymbolic());
197 
198 		tr.reset(detached.name());
199 		head = repo.exactRef("HEAD");
200 		assertEquals(detached, head.getObjectId());
201 		assertFalse(head.isSymbolic());
202 	}
203 
204 	@Test
205 	public void amendRef() throws Exception {
206 		RevCommit root = tr.commit()
207 				.add("todelete", "to be deleted")
208 				.create();
209 		RevCommit orig = tr.commit().parent(root)
210 				.rm("todelete")
211 				.add("foo", "foo contents")
212 				.add("bar", "bar contents")
213 				.add("dir/baz", "baz contents")
214 				.create();
215 		rw.parseBody(orig);
216 		tr.branch("master").update(orig);
217 		assertEquals("foo contents", blobAsString(orig, "foo"));
218 		assertEquals("bar contents", blobAsString(orig, "bar"));
219 		assertEquals("baz contents", blobAsString(orig, "dir/baz"));
220 
221 		RevCommit amended = tr.amendRef("master")
222 				.tick(3)
223 				.add("bar", "fixed bar contents")
224 				.create();
225 		assertEquals(amended, repo.exactRef("refs/heads/master").getObjectId());
226 		rw.parseBody(amended);
227 
228 		assertEquals(1, amended.getParentCount());
229 		assertEquals(root, amended.getParent(0));
230 		assertEquals(orig.getFullMessage(), amended.getFullMessage());
231 		assertEquals(orig.getAuthorIdent(), amended.getAuthorIdent());
232 
233 		// Committer name/email is the same, but time was incremented.
234 		assertEquals(new PersonIdent(orig.getCommitterIdent(), new Date(0)),
235 				new PersonIdent(amended.getCommitterIdent(), new Date(0)));
236 		assertTrue(orig.getCommitTime() < amended.getCommitTime());
237 
238 		assertEquals("foo contents", blobAsString(amended, "foo"));
239 		assertEquals("fixed bar contents", blobAsString(amended, "bar"));
240 		assertEquals("baz contents", blobAsString(amended, "dir/baz"));
241 		assertNull(TreeWalk.forPath(repo, "todelete", amended.getTree()));
242 	}
243 
244 	@Test
245 	public void amendHead() throws Exception {
246 		repo.updateRef("HEAD").link("refs/heads/master");
247 		RevCommit root = tr.commit()
248 				.add("foo", "foo contents")
249 				.create();
250 		RevCommit orig = tr.commit().parent(root)
251 				.message("original message")
252 				.add("bar", "bar contents")
253 				.create();
254 		tr.branch("master").update(orig);
255 
256 		RevCommit amended = tr.amendRef("HEAD")
257 				.add("foo", "fixed foo contents")
258 				.create();
259 
260 		Ref head = repo.exactRef(Constants.HEAD);
261 		assertEquals(amended, head.getObjectId());
262 		assertTrue(head.isSymbolic());
263 		assertEquals("refs/heads/master", head.getTarget().getName());
264 
265 		rw.parseBody(amended);
266 		assertEquals("original message", amended.getFullMessage());
267 		assertEquals("fixed foo contents", blobAsString(amended, "foo"));
268 		assertEquals("bar contents", blobAsString(amended, "bar"));
269 	}
270 
271 	@Test
272 	public void amendCommit() throws Exception {
273 		RevCommit root = tr.commit()
274 				.add("foo", "foo contents")
275 				.create();
276 		RevCommit orig = tr.commit().parent(root)
277 				.message("original message")
278 				.add("bar", "bar contents")
279 				.create();
280 		RevCommit amended = tr.amend(orig.copy())
281 				.add("foo", "fixed foo contents")
282 				.create();
283 
284 		rw.parseBody(amended);
285 		assertEquals("original message", amended.getFullMessage());
286 		assertEquals("fixed foo contents", blobAsString(amended, "foo"));
287 		assertEquals("bar contents", blobAsString(amended, "bar"));
288 	}
289 
290 	@Test
291 	public void commitToUnbornHead() throws Exception {
292 		repo.updateRef("HEAD").link("refs/heads/master");
293 		RevCommit root = tr.branch("HEAD").commit().create();
294 		Ref ref = repo.exactRef(Constants.HEAD);
295 		assertEquals(root, ref.getObjectId());
296 		assertTrue(ref.isSymbolic());
297 		assertEquals("refs/heads/master", ref.getTarget().getName());
298 	}
299 
300 	@Test
301 	public void cherryPick() throws Exception {
302 		repo.updateRef("HEAD").link("refs/heads/master");
303 		RevCommit head = tr.branch("master").commit()
304 				.add("foo", "foo contents\n")
305 				.create();
306 		rw.parseBody(head);
307 		RevCommit toPick = tr.commit()
308 				.parent(tr.commit().create()) // Can't cherry-pick root.
309 				.author(new PersonIdent("Cherrypick Author", "cpa@example.com",
310 						tr.getDate(), tr.getTimeZone()))
311 				.author(new PersonIdent("Cherrypick Committer", "cpc@example.com",
312 						tr.getDate(), tr.getTimeZone()))
313 				.message("message to cherry-pick")
314 				.add("bar", "bar contents\n")
315 				.create();
316 		RevCommit result = tr.cherryPick(toPick);
317 		rw.parseBody(result);
318 
319 		Ref headRef = tr.getRepository().exactRef("HEAD");
320 		assertEquals(result, headRef.getObjectId());
321 		assertTrue(headRef.isSymbolic());
322 		assertEquals("refs/heads/master", headRef.getLeaf().getName());
323 
324 		assertEquals(1, result.getParentCount());
325 		assertEquals(head, result.getParent(0));
326 		assertEquals(toPick.getAuthorIdent(), result.getAuthorIdent());
327 
328 		// Committer name/email matches default, and time was incremented.
329 		assertEquals(new PersonIdent(head.getCommitterIdent(), new Date(0)),
330 				new PersonIdent(result.getCommitterIdent(), new Date(0)));
331 		assertTrue(toPick.getCommitTime() < result.getCommitTime());
332 
333 		assertEquals("message to cherry-pick", result.getFullMessage());
334 		assertEquals("foo contents\n", blobAsString(result, "foo"));
335 		assertEquals("bar contents\n", blobAsString(result, "bar"));
336 	}
337 
338 	@Test
339 	public void cherryPickWithContentMerge() throws Exception {
340 		RevCommit base = tr.branch("HEAD").commit()
341 				.add("foo", "foo contents\n\n")
342 				.create();
343 		tr.branch("HEAD").commit()
344 				.add("foo", "foo contents\n\nlast line\n")
345 				.create();
346 		RevCommit toPick = tr.commit()
347 				.message("message to cherry-pick")
348 				.parent(base)
349 				.add("foo", "changed foo contents\n\n")
350 				.create();
351 		RevCommit result = tr.cherryPick(toPick);
352 		rw.parseBody(result);
353 
354 		assertEquals("message to cherry-pick", result.getFullMessage());
355 		assertEquals("changed foo contents\n\nlast line\n",
356 				blobAsString(result, "foo"));
357 	}
358 
359 	@Test
360 	public void cherryPickWithIdenticalContents() throws Exception {
361 		RevCommit base = tr.branch("HEAD").commit().add("foo", "foo contents\n")
362 				.create();
363 		RevCommit head = tr.branch("HEAD").commit()
364 				.parent(base)
365 				.add("bar", "bar contents\n")
366 				.create();
367 		RevCommit toPick = tr.commit()
368 				.parent(base)
369 				.message("message to cherry-pick")
370 				.add("bar", "bar contents\n")
371 				.create();
372 		assertNotEquals(head, toPick);
373 		assertNull(tr.cherryPick(toPick));
374 		assertEquals(head, repo.exactRef("HEAD").getObjectId());
375 	}
376 
377 	private String blobAsString(AnyObjectId treeish, String path)
378 			throws Exception {
379 		RevObject obj = tr.get(rw.parseTree(treeish), path);
380 		assertSame(RevBlob.class, obj.getClass());
381 		ObjectLoader loader = rw.getObjectReader().open(obj);
382 		return new String(loader.getCachedBytes(), UTF_8);
383 	}
384 }