/* * Copyright (C) 2010, Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available * under the terms of the Eclipse Distribution License v1.0 which * accompanies this distribution, is reproduced below, and is * available at http://www.eclipse.org/org/documents/edl-v10.php * * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Eclipse Foundation, Inc. nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.eclipse.jgit.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.SymbolicRef; import org.junit.Before; import org.junit.Test; public class RefMapTest { private static final ObjectId ID_ONE = ObjectId .fromString("41eb0d88f833b558bddeb269b7ab77399cdf98ed"); private static final ObjectId ID_TWO = ObjectId .fromString("698dd0b8d0c299f080559a1cffc7fe029479a408"); private RefList<Ref> packed; private RefList<Ref> loose; private RefList<Ref> resolved; @Before public void setUp() throws Exception { packed = RefList.emptyList(); loose = RefList.emptyList(); resolved = RefList.emptyList(); } @Test public void testEmpty_NoPrefix1() { RefMap map = new RefMap("", packed, loose, resolved); assertTrue(map.isEmpty()); // before size was computed assertEquals(0, map.size()); assertTrue(map.isEmpty()); // after size was computed assertFalse(map.entrySet().iterator().hasNext()); assertFalse(map.keySet().iterator().hasNext()); assertFalse(map.containsKey("a")); assertNull(map.get("a")); } @Test public void testEmpty_NoPrefix2() { RefMap map = new RefMap(); assertTrue(map.isEmpty()); // before size was computed assertEquals(0, map.size()); assertTrue(map.isEmpty()); // after size was computed assertFalse(map.entrySet().iterator().hasNext()); assertFalse(map.keySet().iterator().hasNext()); assertFalse(map.containsKey("a")); assertNull(map.get("a")); } @Test public void testNotEmpty_NoPrefix() { final Ref master = newRef("refs/heads/master", ID_ONE); packed = toList(master); RefMap map = new RefMap("", packed, loose, resolved); assertFalse(map.isEmpty()); // before size was computed assertEquals(1, map.size()); assertFalse(map.isEmpty()); // after size was computed assertSame(master, map.values().iterator().next()); } @Test public void testEmpty_WithPrefix() { final Ref master = newRef("refs/heads/master", ID_ONE); packed = toList(master); RefMap map = new RefMap("refs/tags/", packed, loose, resolved); assertTrue(map.isEmpty()); // before size was computed assertEquals(0, map.size()); assertTrue(map.isEmpty()); // after size was computed assertFalse(map.entrySet().iterator().hasNext()); assertFalse(map.keySet().iterator().hasNext()); } @Test public void testNotEmpty_WithPrefix() { final Ref master = newRef("refs/heads/master", ID_ONE); packed = toList(master); RefMap map = new RefMap("refs/heads/", packed, loose, resolved); assertFalse(map.isEmpty()); // before size was computed assertEquals(1, map.size()); assertFalse(map.isEmpty()); // after size was computed assertSame(master, map.values().iterator().next()); } @Test public void testClear() { final Ref master = newRef("refs/heads/master", ID_ONE); loose = toList(master); RefMap map = new RefMap("", packed, loose, resolved); assertSame(master, map.get("refs/heads/master")); map.clear(); assertNull(map.get("refs/heads/master")); assertTrue(map.isEmpty()); assertEquals(0, map.size()); } @Test public void testIterator_RefusesRemove() { final Ref master = newRef("refs/heads/master", ID_ONE); loose = toList(master); RefMap map = new RefMap("", packed, loose, resolved); Iterator<Ref> itr = map.values().iterator(); assertTrue(itr.hasNext()); assertSame(master, itr.next()); try { itr.remove(); fail("iterator allowed remove"); } catch (UnsupportedOperationException err) { // expected } } @Test public void testIterator_FailsAtEnd() { final Ref master = newRef("refs/heads/master", ID_ONE); loose = toList(master); RefMap map = new RefMap("", packed, loose, resolved); Iterator<Ref> itr = map.values().iterator(); assertTrue(itr.hasNext()); assertSame(master, itr.next()); try { itr.next(); fail("iterator allowed next"); } catch (NoSuchElementException err) { // expected } } @Test public void testIterator_MissingUnresolvedSymbolicRefIsBug() { final Ref master = newRef("refs/heads/master", ID_ONE); final Ref headR = newRef("HEAD", master); loose = toList(master); // loose should have added newRef("HEAD", "refs/heads/master") resolved = toList(headR); RefMap map = new RefMap("", packed, loose, resolved); Iterator<Ref> itr = map.values().iterator(); try { itr.hasNext(); fail("iterator did not catch bad input"); } catch (IllegalStateException err) { // expected } } @Test public void testMerge_HeadMaster() { final Ref master = newRef("refs/heads/master", ID_ONE); final Ref headU = newRef("HEAD", "refs/heads/master"); final Ref headR = newRef("HEAD", master); loose = toList(headU, master); resolved = toList(headR); RefMap map = new RefMap("", packed, loose, resolved); assertEquals(2, map.size()); assertFalse(map.isEmpty()); assertTrue(map.containsKey("refs/heads/master")); assertSame(master, map.get("refs/heads/master")); // resolved overrides loose given same name assertSame(headR, map.get("HEAD")); Iterator<Ref> itr = map.values().iterator(); assertTrue(itr.hasNext()); assertSame(headR, itr.next()); assertTrue(itr.hasNext()); assertSame(master, itr.next()); assertFalse(itr.hasNext()); } @Test public void testMerge_PackedLooseLoose() { final Ref refA = newRef("A", ID_ONE); final Ref refB_ONE = newRef("B", ID_ONE); final Ref refB_TWO = newRef("B", ID_TWO); final Ref refc = newRef("c", ID_ONE); packed = toList(refA, refB_ONE); loose = toList(refB_TWO, refc); RefMap map = new RefMap("", packed, loose, resolved); assertEquals(3, map.size()); assertFalse(map.isEmpty()); assertTrue(map.containsKey(refA.getName())); assertSame(refA, map.get(refA.getName())); // loose overrides packed given same name assertSame(refB_TWO, map.get(refB_ONE.getName())); Iterator<Ref> itr = map.values().iterator(); assertTrue(itr.hasNext()); assertSame(refA, itr.next()); assertTrue(itr.hasNext()); assertSame(refB_TWO, itr.next()); assertTrue(itr.hasNext()); assertSame(refc, itr.next()); assertFalse(itr.hasNext()); } @Test public void testMerge_WithPrefix() { final Ref a = newRef("refs/heads/A", ID_ONE); final Ref b = newRef("refs/heads/foo/bar/B", ID_TWO); final Ref c = newRef("refs/heads/foo/rab/C", ID_TWO); final Ref g = newRef("refs/heads/g", ID_ONE); packed = toList(a, b, c, g); RefMap map = new RefMap("refs/heads/foo/", packed, loose, resolved); assertEquals(2, map.size()); assertSame(b, map.get("bar/B")); assertSame(c, map.get("rab/C")); assertNull(map.get("refs/heads/foo/bar/B")); assertNull(map.get("refs/heads/A")); assertTrue(map.containsKey("bar/B")); assertTrue(map.containsKey("rab/C")); assertFalse(map.containsKey("refs/heads/foo/bar/B")); assertFalse(map.containsKey("refs/heads/A")); Iterator<Map.Entry<String, Ref>> itr = map.entrySet().iterator(); Map.Entry<String, Ref> ent; assertTrue(itr.hasNext()); ent = itr.next(); assertEquals("bar/B", ent.getKey()); assertSame(b, ent.getValue()); assertTrue(itr.hasNext()); ent = itr.next(); assertEquals("rab/C", ent.getKey()); assertSame(c, ent.getValue()); assertFalse(itr.hasNext()); } @Test public void testPut_KeyMustMatchName_NoPrefix() { final Ref refA = newRef("refs/heads/A", ID_ONE); RefMap map = new RefMap("", packed, loose, resolved); try { map.put("FOO", refA); fail("map accepted invalid key/value pair"); } catch (IllegalArgumentException err) { // expected } } @Test public void testPut_KeyMustMatchName_WithPrefix() { final Ref refA = newRef("refs/heads/A", ID_ONE); RefMap map = new RefMap("refs/heads/", packed, loose, resolved); try { map.put("FOO", refA); fail("map accepted invalid key/value pair"); } catch (IllegalArgumentException err) { // expected } } @Test public void testPut_NoPrefix() { final Ref refA_one = newRef("refs/heads/A", ID_ONE); final Ref refA_two = newRef("refs/heads/A", ID_TWO); packed = toList(refA_one); RefMap map = new RefMap("", packed, loose, resolved); assertSame(refA_one, map.get(refA_one.getName())); assertSame(refA_one, map.put(refA_one.getName(), refA_two)); // map changed, but packed, loose did not assertSame(refA_two, map.get(refA_one.getName())); assertSame(refA_one, packed.get(0)); assertEquals(0, loose.size()); assertSame(refA_two, map.put(refA_one.getName(), refA_one)); assertSame(refA_one, map.get(refA_one.getName())); } @Test public void testPut_WithPrefix() { final Ref refA_one = newRef("refs/heads/A", ID_ONE); final Ref refA_two = newRef("refs/heads/A", ID_TWO); packed = toList(refA_one); RefMap map = new RefMap("refs/heads/", packed, loose, resolved); assertSame(refA_one, map.get("A")); assertSame(refA_one, map.put("A", refA_two)); // map changed, but packed, loose did not assertSame(refA_two, map.get("A")); assertSame(refA_one, packed.get(0)); assertEquals(0, loose.size()); assertSame(refA_two, map.put("A", refA_one)); assertSame(refA_one, map.get("A")); } @Test public void testPut_CollapseResolved() { final Ref master = newRef("refs/heads/master", ID_ONE); final Ref headU = newRef("HEAD", "refs/heads/master"); final Ref headR = newRef("HEAD", master); final Ref a = newRef("refs/heads/A", ID_ONE); loose = toList(headU, master); resolved = toList(headR); RefMap map = new RefMap("", packed, loose, resolved); assertNull(map.put(a.getName(), a)); assertSame(a, map.get(a.getName())); assertSame(headR, map.get("HEAD")); } @Test public void testRemove() { final Ref master = newRef("refs/heads/master", ID_ONE); final Ref headU = newRef("HEAD", "refs/heads/master"); final Ref headR = newRef("HEAD", master); packed = toList(master); loose = toList(headU, master); resolved = toList(headR); RefMap map = new RefMap("", packed, loose, resolved); assertNull(map.remove("not.a.reference")); assertSame(master, map.remove("refs/heads/master")); assertNull(map.get("refs/heads/master")); assertSame(headR, map.remove("HEAD")); assertNull(map.get("HEAD")); assertTrue(map.isEmpty()); } @Test public void testToString_NoPrefix() { final Ref a = newRef("refs/heads/A", ID_ONE); final Ref b = newRef("refs/heads/B", ID_TWO); packed = toList(a, b); StringBuilder exp = new StringBuilder(); exp.append("["); exp.append(a.toString()); exp.append(", "); exp.append(b.toString()); exp.append("]"); RefMap map = new RefMap("", packed, loose, resolved); assertEquals(exp.toString(), map.toString()); } @Test public void testToString_WithPrefix() { final Ref a = newRef("refs/heads/A", ID_ONE); final Ref b = newRef("refs/heads/foo/B", ID_TWO); final Ref c = newRef("refs/heads/foo/C", ID_TWO); final Ref g = newRef("refs/heads/g", ID_ONE); packed = toList(a, b, c, g); StringBuilder exp = new StringBuilder(); exp.append("["); exp.append(b.toString()); exp.append(", "); exp.append(c.toString()); exp.append("]"); RefMap map = new RefMap("refs/heads/foo/", packed, loose, resolved); assertEquals(exp.toString(), map.toString()); } @Test public void testEntryType() { final Ref a = newRef("refs/heads/A", ID_ONE); final Ref b = newRef("refs/heads/B", ID_TWO); packed = toList(a, b); RefMap map = new RefMap("refs/heads/", packed, loose, resolved); Iterator<Map.Entry<String, Ref>> itr = map.entrySet().iterator(); Map.Entry<String, Ref> ent_a = itr.next(); Map.Entry<String, Ref> ent_b = itr.next(); assertEquals(ent_a.hashCode(), "A".hashCode()); assertEquals(ent_a, ent_a); assertFalse(ent_a.equals(ent_b)); assertEquals(a.toString(), ent_a.toString()); } @Test public void testEntryTypeSet() { final Ref refA_one = newRef("refs/heads/A", ID_ONE); final Ref refA_two = newRef("refs/heads/A", ID_TWO); packed = toList(refA_one); RefMap map = new RefMap("refs/heads/", packed, loose, resolved); assertSame(refA_one, map.get("A")); Map.Entry<String, Ref> ent = map.entrySet().iterator().next(); assertEquals("A", ent.getKey()); assertSame(refA_one, ent.getValue()); assertSame(refA_one, ent.setValue(refA_two)); assertSame(refA_two, ent.getValue()); assertSame(refA_two, map.get("A")); assertEquals(1, map.size()); } private static RefList<Ref> toList(Ref... refs) { RefList.Builder<Ref> b = new RefList.Builder<Ref>(refs.length); b.addAll(refs, 0, refs.length); return b.toRefList(); } private static Ref newRef(String name, String dst) { return newRef(name, new ObjectIdRef.Unpeeled(Ref.Storage.NEW, dst, null)); } private static Ref newRef(String name, Ref dst) { return new SymbolicRef(name, dst); } private static Ref newRef(String name, ObjectId id) { return new ObjectIdRef.Unpeeled(Ref.Storage.LOOSE, name, id); } }