View Javadoc
1   /*
2    * Copyright (C) 2019, Google LLC.
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.assertNull;
48  
49  import org.eclipse.jgit.lib.ObjectId;
50  import org.eclipse.jgit.revwalk.filter.MessageRevFilter;
51  import org.eclipse.jgit.revwalk.filter.RevFilter;
52  import org.junit.Test;
53  
54  public class FirstParentRevWalkTest extends RevWalkTestCase {
55  	@Test
56  	public void testStringOfPearls() throws Exception {
57  		RevCommit a = commit();
58  		RevCommit b = commit(a);
59  		RevCommit c = commit(b);
60  
61  		rw.reset();
62  		rw.setFirstParent(true);
63  		markStart(c);
64  		assertCommit(c, rw.next());
65  		assertCommit(b, rw.next());
66  		assertCommit(a, rw.next());
67  		assertNull(rw.next());
68  	}
69  
70  	@Test
71  	public void testSideBranch() throws Exception {
72  		RevCommit a = commit();
73  		RevCommit b1 = commit(a);
74  		RevCommit b2 = commit(a);
75  		RevCommit c1 = commit(b1);
76  		RevCommit c2 = commit(b2);
77  		RevCommit d = commit(c1, c2);
78  
79  		rw.reset();
80  		rw.setFirstParent(true);
81  		markStart(d);
82  		assertCommit(d, rw.next());
83  		assertCommit(c1, rw.next());
84  		assertCommit(b1, rw.next());
85  		assertCommit(a, rw.next());
86  		assertNull(rw.next());
87  	}
88  
89  	@Test
90  	public void testSecondParentAncestorOfFirstParent() throws Exception {
91  		RevCommit a = commit();
92  		RevCommit b = commit(a);
93  		RevCommit c = commit(b, a);
94  
95  		rw.reset();
96  		rw.setFirstParent(true);
97  		markStart(c);
98  		assertCommit(c, rw.next());
99  		assertCommit(b, rw.next());
100 		assertCommit(a, rw.next());
101 		assertNull(rw.next());
102 	}
103 
104 	@Test
105 	public void testFirstParentMultipleOccurrences() throws Exception {
106 		RevCommit a = commit();
107 		RevCommit b = commit(a);
108 		RevCommit c = commit(b);
109 		RevCommit d = commit(b);
110 
111 		rw.reset();
112 		rw.setFirstParent(true);
113 		markStart(c);
114 		markStart(d);
115 		assertCommit(d, rw.next());
116 		assertCommit(c, rw.next());
117 		assertCommit(b, rw.next());
118 		assertCommit(a, rw.next());
119 		assertNull(rw.next());
120 	}
121 
122 	@Test
123 	public void testReachableAlongFirstAndLaterParents() throws Exception {
124 		RevCommit a = commit();
125 		RevCommit b1 = commit(a);
126 		RevCommit b2 = commit(a);
127 		RevCommit b3 = commit(a);
128 		RevCommit c = commit(b1, b2);
129 		RevCommit d = commit(b2, b3);
130 
131 		rw.reset();
132 		rw.setFirstParent(true);
133 		markStart(c);
134 		markStart(d);
135 		assertCommit(d, rw.next());
136 		assertCommit(c, rw.next());
137 		// b3 is only reachable from c's second parent.
138 		// b2 is reachable from c's second parent but d's first parent.
139 		assertCommit(b2, rw.next());
140 		assertCommit(b1, rw.next());
141 		assertCommit(a, rw.next());
142 		assertNull(rw.next());
143 	}
144 
145 	@Test
146 	public void testStartCommitReachableOnlyFromLaterParents()
147 			throws Exception {
148 		RevCommit a = commit();
149 		RevCommit b1 = commit(a);
150 		RevCommit b2 = commit(a);
151 		RevCommit c = commit(b1, b2);
152 
153 		rw.reset();
154 		rw.setFirstParent(true);
155 		markStart(c);
156 		markStart(b2);
157 		assertCommit(c, rw.next());
158 		// b2 is only reachable from second parent, but is itself a start
159 		// commit.
160 		assertCommit(b2, rw.next());
161 		assertCommit(b1, rw.next());
162 		assertCommit(a, rw.next());
163 		assertNull(rw.next());
164 	}
165 
166 	@Test
167 	public void testRevFilter() throws Exception {
168 		RevCommit a = commit();
169 		RevCommit b1 = commitBuilder().parent(a).message("commit b1").create();
170 		RevCommit b2 = commitBuilder().parent(a).message("commit b2").create();
171 		RevCommit c = commit(b1, b2);
172 
173 		rw.reset();
174 		rw.setFirstParent(true);
175 		rw.setRevFilter(MessageRevFilter.create("commit b"));
176 		rw.markStart(c);
177 		assertCommit(b1, rw.next());
178 		assertNull(rw.next());
179 	}
180 
181 	@Test
182 	public void testTopoSort() throws Exception {
183 		RevCommit a = commit();
184 		RevCommit b1 = commit(a);
185 		RevCommit b2 = commit(a);
186 		RevCommit c = commit(b1, b2);
187 
188 		rw.reset();
189 		rw.sort(RevSort.TOPO);
190 		rw.setFirstParent(true);
191 		markStart(c);
192 		assertCommit(c, rw.next());
193 		assertCommit(b1, rw.next());
194 		assertCommit(a, rw.next());
195 		assertNull(rw.next());
196 	}
197 
198 	@Test
199 	public void testCommitTimeSort() throws Exception {
200 		RevCommit a = commit();
201 		RevCommit b1 = commit(a);
202 		RevCommit b2 = commit(a);
203 		RevCommit c = commit(b1, b2);
204 
205 		rw.reset();
206 		rw.sort(RevSort.COMMIT_TIME_DESC);
207 		rw.setFirstParent(true);
208 		markStart(c);
209 		assertCommit(c, rw.next());
210 		assertCommit(b1, rw.next());
211 		assertCommit(a, rw.next());
212 		assertNull(rw.next());
213 	}
214 
215 	@Test
216 	public void testReverseSort() throws Exception {
217 		RevCommit a = commit();
218 		RevCommit b1 = commit(a);
219 		RevCommit b2 = commit(a);
220 		RevCommit c = commit(b1, b2);
221 
222 		rw.reset();
223 		rw.sort(RevSort.REVERSE);
224 		rw.setFirstParent(true);
225 		markStart(c);
226 		assertCommit(a, rw.next());
227 		assertCommit(b1, rw.next());
228 		assertCommit(c, rw.next());
229 		assertNull(rw.next());
230 	}
231 
232 	@Test
233 	public void testBoundarySort() throws Exception {
234 		RevCommit a = commit();
235 		RevCommit b = commit(a);
236 		RevCommit c1 = commit(b);
237 		RevCommit c2 = commit(b);
238 		RevCommit d = commit(c1, c2);
239 
240 		rw.reset();
241 		rw.sort(RevSort.BOUNDARY);
242 		rw.setFirstParent(true);
243 		markStart(d);
244 		markUninteresting(a);
245 		assertCommit(d, rw.next());
246 		assertCommit(c1, rw.next());
247 		assertCommit(b, rw.next());
248 		assertCommit(a, rw.next());
249 		assertNull(rw.next());
250 	}
251 
252 	@Test
253 	public void testFirstParentOfFirstParentMarkedUninteresting()
254 			throws Exception {
255 		RevCommit a = commit();
256 		RevCommit b1 = commit(a);
257 		RevCommit b2 = commit(a);
258 		RevCommit c1 = commit(b1);
259 		RevCommit c2 = commit(b2);
260 		RevCommit d = commit(c1, c2);
261 
262 		rw.reset();
263 		rw.setFirstParent(true);
264 		markStart(d);
265 		markUninteresting(b1);
266 		assertCommit(d, rw.next());
267 		assertCommit(c1, rw.next());
268 		assertNull(rw.next());
269 	}
270 
271 	@Test
272 	public void testUnparsedFirstParentOfFirstParentMarkedUninteresting()
273 			throws Exception {
274 		ObjectId a = unparsedCommit();
275 		ObjectId b1 = unparsedCommit(a);
276 		ObjectId b2 = unparsedCommit(a);
277 		ObjectId c1 = unparsedCommit(b1);
278 		ObjectId c2 = unparsedCommit(b2);
279 		ObjectId d = unparsedCommit(c1, c2);
280 
281 		rw.reset();
282 		rw.setFirstParent(true);
283 		RevCommit parsedD = rw.parseCommit(d);
284 		markStart(parsedD);
285 		markUninteresting(rw.parseCommit(b1));
286 		assertCommit(parsedD, rw.next());
287 		assertCommit(rw.parseCommit(c1), rw.next());
288 		assertNull(rw.next());
289 	}
290 
291 	@Test
292 	public void testFirstParentMarkedUninteresting() throws Exception {
293 		RevCommit a = commit();
294 		RevCommit b1 = commit(a);
295 		RevCommit b2 = commit(a);
296 		RevCommit c = commit(b1, b2);
297 
298 		rw.reset();
299 		rw.setFirstParent(true);
300 		markStart(c);
301 		markUninteresting(b1);
302 		assertCommit(c, rw.next());
303 		assertNull(rw.next());
304 	}
305 
306 	@Test
307 	public void testUnparsedFirstParentMarkedUninteresting() throws Exception {
308 		ObjectId a = unparsedCommit();
309 		ObjectId b1 = unparsedCommit(a);
310 		ObjectId b2 = unparsedCommit(a);
311 		ObjectId c = unparsedCommit(b1, b2);
312 
313 		rw.reset();
314 		rw.setFirstParent(true);
315 		RevCommit parsedC = rw.parseCommit(c);
316 		markStart(parsedC);
317 		markUninteresting(rw.parseCommit(b1));
318 		assertCommit(parsedC, rw.next());
319 		assertNull(rw.next());
320 	}
321 
322 	@Test
323 	public void testUninterestingCommitWithTwoParents() throws Exception {
324 		RevCommit a = commit();
325 		RevCommit b = commit(a);
326 		RevCommit c1 = commit(b);
327 		RevCommit c2 = commit(b);
328 		RevCommit d = commit(c1);
329 		RevCommit e = commit(c1, c2);
330 
331 		RevCommit uA = commit(a, b);
332 		RevCommit uB1 = commit(uA, c2);
333 		RevCommit uB2 = commit(uA, d);
334 		RevCommit uninteresting = commit(uB1, uB2);
335 
336 		rw.reset();
337 		rw.setFirstParent(true);
338 		markStart(e);
339 		markUninteresting(uninteresting);
340 
341 		assertCommit(e, rw.next());
342 		assertNull(rw.next());
343 	}
344 
345 	/**
346 	 * This fails if we try to propagate flags before parsing commits.
347 	 *
348 	 * @throws Exception
349 	 */
350 	@Test
351 	public void testUnparsedUninterestingCommitWithTwoParents()
352 			throws Exception {
353 		ObjectId a = unparsedCommit();
354 		ObjectId b = unparsedCommit(a);
355 		ObjectId c1 = unparsedCommit(b);
356 		ObjectId c2 = unparsedCommit(b);
357 		ObjectId d = unparsedCommit(c1);
358 		ObjectId e = unparsedCommit(c1, c2);
359 
360 		ObjectId uA = unparsedCommit(a, b);
361 		ObjectId uB1 = unparsedCommit(uA, c2);
362 		ObjectId uB2 = unparsedCommit(uA, d);
363 		ObjectId uninteresting = unparsedCommit(uB1, uB2);
364 
365 		rw.reset();
366 		rw.setFirstParent(true);
367 		RevCommit parsedE = rw.parseCommit(e);
368 		markStart(parsedE);
369 		markUninteresting(rw.parseCommit(uninteresting));
370 
371 		assertCommit(parsedE, rw.next());
372 		assertNull(rw.next());
373 	}
374 
375 	@Test
376 	public void testDepthWalk() throws Exception {
377 		RevCommit a = commit();
378 		RevCommit b1 = commit(a);
379 		RevCommit b2 = commit(a);
380 		RevCommit c = commit(b1, b2);
381 
382 		try (DepthWalk.RevWalk dw = new DepthWalk.RevWalk(db, 1)) {
383 			dw.setFirstParent(true);
384 			dw.markRoot(dw.parseCommit(c));
385 			dw.markStart(dw.parseCommit(c));
386 			assertEquals(c, dw.next());
387 			assertEquals(b1, dw.next());
388 			assertNull(dw.next());
389 		}
390 	}
391 
392 	@Test
393 	public void testDoNotRewriteParents() throws Exception {
394 		RevCommit a = commit();
395 		RevCommit b1 = commit(a);
396 		RevCommit b2 = commit(a);
397 		RevCommit c = commit(b1, b2);
398 
399 		rw.reset();
400 		rw.setFirstParent(true);
401 		rw.setRewriteParents(false);
402 		markStart(c);
403 		assertCommit(c, rw.next());
404 		assertCommit(b1, rw.next());
405 		assertCommit(a, rw.next());
406 		assertNull(rw.next());
407 	}
408 
409 	@Test(expected = IllegalStateException.class)
410 	public void testMarkStartBeforeSetFirstParent() throws Exception {
411 		RevCommit a = commit();
412 
413 		rw.reset();
414 		markStart(a);
415 		rw.setFirstParent(true);
416 	}
417 
418 	@Test(expected = IllegalStateException.class)
419 	public void testMergeBaseWithFirstParentNotAllowed() throws Exception {
420 		RevCommit a = commit();
421 
422 		rw.reset();
423 		rw.setFirstParent(true);
424 		rw.setRevFilter(RevFilter.MERGE_BASE);
425 		markStart(a);
426 		assertNull(rw.next());
427 	}
428 }