View Javadoc
1   /*
2    * Copyright (C) 2010, 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.util;
12  
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertFalse;
15  import static org.junit.Assert.assertNull;
16  import static org.junit.Assert.assertSame;
17  import static org.junit.Assert.assertTrue;
18  import static org.junit.Assert.fail;
19  
20  import java.util.Iterator;
21  import java.util.Map;
22  import java.util.NoSuchElementException;
23  
24  import org.eclipse.jgit.lib.ObjectId;
25  import org.eclipse.jgit.lib.ObjectIdRef;
26  import org.eclipse.jgit.lib.Ref;
27  import org.eclipse.jgit.lib.SymbolicRef;
28  import org.junit.Before;
29  import org.junit.Test;
30  
31  public class RefMapTest {
32  	private static final ObjectId ID_ONE = ObjectId
33  			.fromString("41eb0d88f833b558bddeb269b7ab77399cdf98ed");
34  
35  	private static final ObjectId ID_TWO = ObjectId
36  			.fromString("698dd0b8d0c299f080559a1cffc7fe029479a408");
37  
38  	private RefList<Ref> packed;
39  
40  	private RefList<Ref> loose;
41  
42  	private RefList<Ref> resolved;
43  
44  	@Before
45  	public void setUp() throws Exception {
46  		packed = RefList.emptyList();
47  		loose = RefList.emptyList();
48  		resolved = RefList.emptyList();
49  	}
50  
51  	@Test
52  	public void testEmpty_NoPrefix1() {
53  		RefMap map = new RefMap("", packed, loose, resolved);
54  		assertTrue(map.isEmpty()); // before size was computed
55  		assertEquals(0, map.size());
56  		assertTrue(map.isEmpty()); // after size was computed
57  
58  		assertFalse(map.entrySet().iterator().hasNext());
59  		assertFalse(map.keySet().iterator().hasNext());
60  		assertFalse(map.containsKey("a"));
61  		assertNull(map.get("a"));
62  	}
63  
64  	@Test
65  	public void testEmpty_NoPrefix2() {
66  		RefMap map = new RefMap();
67  		assertTrue(map.isEmpty()); // before size was computed
68  		assertEquals(0, map.size());
69  		assertTrue(map.isEmpty()); // after size was computed
70  
71  		assertFalse(map.entrySet().iterator().hasNext());
72  		assertFalse(map.keySet().iterator().hasNext());
73  		assertFalse(map.containsKey("a"));
74  		assertNull(map.get("a"));
75  	}
76  
77  	@Test
78  	public void testNotEmpty_NoPrefix() {
79  		final Ref master = newRef("refs/heads/master", ID_ONE);
80  		packed = toList(master);
81  
82  		RefMap map = new RefMap("", packed, loose, resolved);
83  		assertFalse(map.isEmpty()); // before size was computed
84  		assertEquals(1, map.size());
85  		assertFalse(map.isEmpty()); // after size was computed
86  		assertSame(master, map.values().iterator().next());
87  	}
88  
89  	@Test
90  	public void testEmpty_WithPrefix() {
91  		final Ref master = newRef("refs/heads/master", ID_ONE);
92  		packed = toList(master);
93  
94  		RefMap map = new RefMap("refs/tags/", packed, loose, resolved);
95  		assertTrue(map.isEmpty()); // before size was computed
96  		assertEquals(0, map.size());
97  		assertTrue(map.isEmpty()); // after size was computed
98  
99  		assertFalse(map.entrySet().iterator().hasNext());
100 		assertFalse(map.keySet().iterator().hasNext());
101 	}
102 
103 	@Test
104 	public void testNotEmpty_WithPrefix() {
105 		final Ref master = newRef("refs/heads/master", ID_ONE);
106 		packed = toList(master);
107 
108 		RefMap map = new RefMap("refs/heads/", packed, loose, resolved);
109 		assertFalse(map.isEmpty()); // before size was computed
110 		assertEquals(1, map.size());
111 		assertFalse(map.isEmpty()); // after size was computed
112 		assertSame(master, map.values().iterator().next());
113 	}
114 
115 	@Test
116 	public void testClear() {
117 		final Ref master = newRef("refs/heads/master", ID_ONE);
118 		loose = toList(master);
119 
120 		RefMap map = new RefMap("", packed, loose, resolved);
121 		assertSame(master, map.get("refs/heads/master"));
122 
123 		map.clear();
124 		assertNull(map.get("refs/heads/master"));
125 		assertTrue(map.isEmpty());
126 		assertEquals(0, map.size());
127 	}
128 
129 	@Test
130 	public void testIterator_RefusesRemove() {
131 		final Ref master = newRef("refs/heads/master", ID_ONE);
132 		loose = toList(master);
133 
134 		RefMap map = new RefMap("", packed, loose, resolved);
135 		Iterator<Ref> itr = map.values().iterator();
136 		assertTrue(itr.hasNext());
137 		assertSame(master, itr.next());
138 		try {
139 			itr.remove();
140 			fail("iterator allowed remove");
141 		} catch (UnsupportedOperationException err) {
142 			// expected
143 		}
144 	}
145 
146 	@Test
147 	public void testIterator_FailsAtEnd() {
148 		final Ref master = newRef("refs/heads/master", ID_ONE);
149 		loose = toList(master);
150 
151 		RefMap map = new RefMap("", packed, loose, resolved);
152 		Iterator<Ref> itr = map.values().iterator();
153 		assertTrue(itr.hasNext());
154 		assertSame(master, itr.next());
155 		try {
156 			itr.next();
157 			fail("iterator allowed next");
158 		} catch (NoSuchElementException err) {
159 			// expected
160 		}
161 	}
162 
163 	@Test
164 	public void testIterator_MissingUnresolvedSymbolicRefIsBug() {
165 		final Ref master = newRef("refs/heads/master", ID_ONE);
166 		final Ref headR = newRef("HEAD", master);
167 
168 		loose = toList(master);
169 		// loose should have added newRef("HEAD", "refs/heads/master")
170 		resolved = toList(headR);
171 
172 		RefMap map = new RefMap("", packed, loose, resolved);
173 		Iterator<Ref> itr = map.values().iterator();
174 		try {
175 			itr.hasNext();
176 			fail("iterator did not catch bad input");
177 		} catch (IllegalStateException err) {
178 			// expected
179 		}
180 	}
181 
182 	@Test
183 	public void testMerge_HeadMaster() {
184 		final Ref master = newRef("refs/heads/master", ID_ONE);
185 		final Ref headU = newRef("HEAD", "refs/heads/master");
186 		final Ref headR = newRef("HEAD", master);
187 
188 		loose = toList(headU, master);
189 		resolved = toList(headR);
190 
191 		RefMap map = new RefMap("", packed, loose, resolved);
192 		assertEquals(2, map.size());
193 		assertFalse(map.isEmpty());
194 		assertTrue(map.containsKey("refs/heads/master"));
195 		assertSame(master, map.get("refs/heads/master"));
196 
197 		// resolved overrides loose given same name
198 		assertSame(headR, map.get("HEAD"));
199 
200 		Iterator<Ref> itr = map.values().iterator();
201 		assertTrue(itr.hasNext());
202 		assertSame(headR, itr.next());
203 		assertTrue(itr.hasNext());
204 		assertSame(master, itr.next());
205 		assertFalse(itr.hasNext());
206 	}
207 
208 	@Test
209 	public void testMerge_PackedLooseLoose() {
210 		final Ref refA = newRef("A", ID_ONE);
211 		final Ref refB_ONE = newRef("B", ID_ONE);
212 		final Ref refB_TWO = newRef("B", ID_TWO);
213 		final Ref refc = newRef("c", ID_ONE);
214 
215 		packed = toList(refA, refB_ONE);
216 		loose = toList(refB_TWO, refc);
217 
218 		RefMap map = new RefMap("", packed, loose, resolved);
219 		assertEquals(3, map.size());
220 		assertFalse(map.isEmpty());
221 		assertTrue(map.containsKey(refA.getName()));
222 		assertSame(refA, map.get(refA.getName()));
223 
224 		// loose overrides packed given same name
225 		assertSame(refB_TWO, map.get(refB_ONE.getName()));
226 
227 		Iterator<Ref> itr = map.values().iterator();
228 		assertTrue(itr.hasNext());
229 		assertSame(refA, itr.next());
230 		assertTrue(itr.hasNext());
231 		assertSame(refB_TWO, itr.next());
232 		assertTrue(itr.hasNext());
233 		assertSame(refc, itr.next());
234 		assertFalse(itr.hasNext());
235 	}
236 
237 	@Test
238 	public void testMerge_WithPrefix() {
239 		final Ref a = newRef("refs/heads/A", ID_ONE);
240 		final Ref b = newRef("refs/heads/foo/bar/B", ID_TWO);
241 		final Ref c = newRef("refs/heads/foo/rab/C", ID_TWO);
242 		final Ref g = newRef("refs/heads/g", ID_ONE);
243 		packed = toList(a, b, c, g);
244 
245 		RefMap map = new RefMap("refs/heads/foo/", packed, loose, resolved);
246 		assertEquals(2, map.size());
247 
248 		assertSame(b, map.get("bar/B"));
249 		assertSame(c, map.get("rab/C"));
250 		assertNull(map.get("refs/heads/foo/bar/B"));
251 		assertNull(map.get("refs/heads/A"));
252 
253 		assertTrue(map.containsKey("bar/B"));
254 		assertTrue(map.containsKey("rab/C"));
255 		assertFalse(map.containsKey("refs/heads/foo/bar/B"));
256 		assertFalse(map.containsKey("refs/heads/A"));
257 
258 		Iterator<Map.Entry<String, Ref>> itr = map.entrySet().iterator();
259 		Map.Entry<String, Ref> ent;
260 		assertTrue(itr.hasNext());
261 		ent = itr.next();
262 		assertEquals("bar/B", ent.getKey());
263 		assertSame(b, ent.getValue());
264 		assertTrue(itr.hasNext());
265 		ent = itr.next();
266 		assertEquals("rab/C", ent.getKey());
267 		assertSame(c, ent.getValue());
268 		assertFalse(itr.hasNext());
269 	}
270 
271 	@Test
272 	public void testPut_KeyMustMatchName_NoPrefix() {
273 		final Ref refA = newRef("refs/heads/A", ID_ONE);
274 		RefMap map = new RefMap("", packed, loose, resolved);
275 		try {
276 			map.put("FOO", refA);
277 			fail("map accepted invalid key/value pair");
278 		} catch (IllegalArgumentException err) {
279 			// expected
280 		}
281 	}
282 
283 	@Test
284 	public void testPut_KeyMustMatchName_WithPrefix() {
285 		final Ref refA = newRef("refs/heads/A", ID_ONE);
286 		RefMap map = new RefMap("refs/heads/", packed, loose, resolved);
287 		try {
288 			map.put("FOO", refA);
289 			fail("map accepted invalid key/value pair");
290 		} catch (IllegalArgumentException err) {
291 			// expected
292 		}
293 	}
294 
295 	@Test
296 	public void testPut_NoPrefix() {
297 		final Ref refA_one = newRef("refs/heads/A", ID_ONE);
298 		final Ref refA_two = newRef("refs/heads/A", ID_TWO);
299 
300 		packed = toList(refA_one);
301 
302 		RefMap map = new RefMap("", packed, loose, resolved);
303 		assertSame(refA_one, map.get(refA_one.getName()));
304 		assertSame(refA_one, map.put(refA_one.getName(), refA_two));
305 
306 		// map changed, but packed, loose did not
307 		assertSame(refA_two, map.get(refA_one.getName()));
308 		assertSame(refA_one, packed.get(0));
309 		assertEquals(0, loose.size());
310 
311 		assertSame(refA_two, map.put(refA_one.getName(), refA_one));
312 		assertSame(refA_one, map.get(refA_one.getName()));
313 	}
314 
315 	@Test
316 	public void testPut_WithPrefix() {
317 		final Ref refA_one = newRef("refs/heads/A", ID_ONE);
318 		final Ref refA_two = newRef("refs/heads/A", ID_TWO);
319 
320 		packed = toList(refA_one);
321 
322 		RefMap map = new RefMap("refs/heads/", packed, loose, resolved);
323 		assertSame(refA_one, map.get("A"));
324 		assertSame(refA_one, map.put("A", refA_two));
325 
326 		// map changed, but packed, loose did not
327 		assertSame(refA_two, map.get("A"));
328 		assertSame(refA_one, packed.get(0));
329 		assertEquals(0, loose.size());
330 
331 		assertSame(refA_two, map.put("A", refA_one));
332 		assertSame(refA_one, map.get("A"));
333 	}
334 
335 	@Test
336 	public void testPut_CollapseResolved() {
337 		final Ref master = newRef("refs/heads/master", ID_ONE);
338 		final Ref headU = newRef("HEAD", "refs/heads/master");
339 		final Ref headR = newRef("HEAD", master);
340 		final Ref a = newRef("refs/heads/A", ID_ONE);
341 
342 		loose = toList(headU, master);
343 		resolved = toList(headR);
344 
345 		RefMap map = new RefMap("", packed, loose, resolved);
346 		assertNull(map.put(a.getName(), a));
347 		assertSame(a, map.get(a.getName()));
348 		assertSame(headR, map.get("HEAD"));
349 	}
350 
351 	@Test
352 	public void testRemove() {
353 		final Ref master = newRef("refs/heads/master", ID_ONE);
354 		final Ref headU = newRef("HEAD", "refs/heads/master");
355 		final Ref headR = newRef("HEAD", master);
356 
357 		packed = toList(master);
358 		loose = toList(headU, master);
359 		resolved = toList(headR);
360 
361 		RefMap map = new RefMap("", packed, loose, resolved);
362 		assertNull(map.remove("not.a.reference"));
363 
364 		assertSame(master, map.remove("refs/heads/master"));
365 		assertNull(map.get("refs/heads/master"));
366 
367 		assertSame(headR, map.remove("HEAD"));
368 		assertNull(map.get("HEAD"));
369 
370 		assertTrue(map.isEmpty());
371 	}
372 
373 	@Test
374 	public void testToString_NoPrefix() {
375 		final Ref a = newRef("refs/heads/A", ID_ONE);
376 		final Ref b = newRef("refs/heads/B", ID_TWO);
377 
378 		packed = toList(a, b);
379 
380 		StringBuilder exp = new StringBuilder();
381 		exp.append("[");
382 		exp.append(a.toString());
383 		exp.append(", ");
384 		exp.append(b.toString());
385 		exp.append("]");
386 
387 		RefMap map = new RefMap("", packed, loose, resolved);
388 		assertEquals(exp.toString(), map.toString());
389 	}
390 
391 	@Test
392 	public void testToString_WithPrefix() {
393 		final Ref a = newRef("refs/heads/A", ID_ONE);
394 		final Ref b = newRef("refs/heads/foo/B", ID_TWO);
395 		final Ref c = newRef("refs/heads/foo/C", ID_TWO);
396 		final Ref g = newRef("refs/heads/g", ID_ONE);
397 
398 		packed = toList(a, b, c, g);
399 
400 		StringBuilder exp = new StringBuilder();
401 		exp.append("[");
402 		exp.append(b.toString());
403 		exp.append(", ");
404 		exp.append(c.toString());
405 		exp.append("]");
406 
407 		RefMap map = new RefMap("refs/heads/foo/", packed, loose, resolved);
408 		assertEquals(exp.toString(), map.toString());
409 	}
410 
411 	@Test
412 	public void testEntryType() {
413 		final Ref a = newRef("refs/heads/A", ID_ONE);
414 		final Ref b = newRef("refs/heads/B", ID_TWO);
415 
416 		packed = toList(a, b);
417 
418 		RefMap map = new RefMap("refs/heads/", packed, loose, resolved);
419 		Iterator<Map.Entry<String, Ref>> itr = map.entrySet().iterator();
420 		Map.Entry<String, Ref> ent_a = itr.next();
421 		Map.Entry<String, Ref> ent_b = itr.next();
422 
423 		assertEquals(ent_a.hashCode(), "A".hashCode());
424 		assertEquals(ent_a, ent_a);
425 		assertFalse(ent_a.equals(ent_b));
426 
427 		assertEquals(a.toString(), ent_a.toString());
428 	}
429 
430 	@Test
431 	public void testEntryTypeSet() {
432 		final Ref refA_one = newRef("refs/heads/A", ID_ONE);
433 		final Ref refA_two = newRef("refs/heads/A", ID_TWO);
434 
435 		packed = toList(refA_one);
436 
437 		RefMap map = new RefMap("refs/heads/", packed, loose, resolved);
438 		assertSame(refA_one, map.get("A"));
439 
440 		Map.Entry<String, Ref> ent = map.entrySet().iterator().next();
441 		assertEquals("A", ent.getKey());
442 		assertSame(refA_one, ent.getValue());
443 
444 		assertSame(refA_one, ent.setValue(refA_two));
445 		assertSame(refA_two, ent.getValue());
446 		assertSame(refA_two, map.get("A"));
447 		assertEquals(1, map.size());
448 	}
449 
450 	private static RefList<Ref> toList(Ref... refs) {
451 		RefList.Builder<Ref> b = new RefList.Builder<>(refs.length);
452 		b.addAll(refs, 0, refs.length);
453 		return b.toRefList();
454 	}
455 
456 	private static Ref newRef(String name, String dst) {
457 		return newRef(name,
458 				new ObjectIdRef.Unpeeled(Ref.Storage.NEW, dst, null));
459 	}
460 
461 	private static Ref newRef(String name, Ref dst) {
462 		return new SymbolicRef(name, dst);
463 	}
464 
465 	private static Ref newRef(String name, ObjectId id) {
466 		return new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, id);
467 	}
468 }