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