Add ImmutableMapTemplate
[yangtools.git] / common / util / src / test / java / org / opendaylight / yangtools / util / OffsetMapTest.java
index 8f95699c83396cd773c723a3febbba2d81c6a6df..bc93d2cfde480884c1428444a720c582d17b9876 100644 (file)
@@ -14,8 +14,9 @@ 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 com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Iterators;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -30,6 +31,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import org.junit.Before;
 import org.junit.Test;
 
 public class OffsetMapTest {
@@ -37,18 +39,27 @@ public class OffsetMapTest {
     private final Map<String, String> threeEntryMap = ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
 
     private ImmutableOffsetMap<String, String> createMap() {
-        return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.copyOf(twoEntryMap);
+        return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.orderedCopyOf(twoEntryMap);
+    }
+
+    private ImmutableOffsetMap<String, String> unorderedMap() {
+        return (ImmutableOffsetMap<String, String>) ImmutableOffsetMap.unorderedCopyOf(twoEntryMap);
+    }
+
+    @Before
+    public void setup() {
+        OffsetMapCache.invalidateCache();
     }
 
-    @Test(expected=IllegalArgumentException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testWrongImmutableConstruction() {
-        new ImmutableOffsetMap.Ordered<String, String>(Collections.<String, Integer>emptyMap(), new String[1]);
+        new ImmutableOffsetMap.Ordered<>(ImmutableMap.of(), new String[1]);
     }
 
     @Test
     public void testCopyEmptyMap() {
         final Map<String, String> source = Collections.emptyMap();
-        final Map<String, String> result = ImmutableOffsetMap.copyOf(source);
+        final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
 
         assertEquals(source, result);
         assertTrue(result instanceof ImmutableMap);
@@ -57,7 +68,7 @@ public class OffsetMapTest {
     @Test
     public void testCopySingletonMap() {
         final Map<String, String> source = Collections.singletonMap("a", "b");
-        final Map<String, String> result = ImmutableOffsetMap.copyOf(source);
+        final Map<String, String> result = ImmutableOffsetMap.orderedCopyOf(source);
 
         assertEquals(source, result);
         assertTrue(result instanceof SharedSingletonMap);
@@ -78,10 +89,10 @@ public class OffsetMapTest {
         assertTrue(Iterators.elementsEqual(twoEntryMap.entrySet().iterator(), map.entrySet().iterator()));
 
         // Should result in the same object
-        assertSame(map, ImmutableOffsetMap.copyOf(map));
+        assertSame(map, ImmutableOffsetMap.orderedCopyOf(map));
 
         final Map<String, String> mutable = map.toModifiableMap();
-        final Map<String, String> copy = ImmutableOffsetMap.copyOf(mutable);
+        final Map<String, String> copy = ImmutableOffsetMap.orderedCopyOf(mutable);
 
         assertEquals(mutable, copy);
         assertEquals(map, copy);
@@ -116,18 +127,21 @@ public class OffsetMapTest {
             map.values().add("v1");
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.values().remove("v1");
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.values().clear();
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
@@ -136,24 +150,28 @@ public class OffsetMapTest {
             it.remove();
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.keySet().add("k1");
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.keySet().clear();
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.keySet().remove("k1");
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
@@ -162,24 +180,28 @@ public class OffsetMapTest {
             it.remove();
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.entrySet().clear();
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.entrySet().add(new SimpleEntry<>("k1", "v1"));
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.entrySet().remove(new SimpleEntry<>("k1", "v1"));
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
@@ -188,30 +210,35 @@ public class OffsetMapTest {
             it.remove();
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.clear();
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.put("k1", "fail");
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.putAll(ImmutableMap.of("k1", "fail"));
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
 
         try {
             map.remove("k1");
             fail();
         } catch (UnsupportedOperationException e) {
+            // OK
         }
     }
 
@@ -303,7 +330,8 @@ public class OffsetMapTest {
         mutable.remove("non-existent");
 
         // Resulting map should be equal, but not the same object
-        final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
+        final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
+                .toUnmodifiableMap();
         assertNotSame(source, result);
         assertEquals(source, result);
 
@@ -320,7 +348,25 @@ public class OffsetMapTest {
         mutable.remove("k1");
         mutable.put("k1", "v1");
 
-        final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
+        final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
+                .toUnmodifiableMap();
+        assertTrue(source.equals(result));
+        assertTrue(result.equals(source));
+
+        // Iterator order must not be preserved
+        assertFalse(Iterators.elementsEqual(source.entrySet().iterator(), result.entrySet().iterator()));
+    }
+
+    @Test
+    public void testReusedOffsetsUnordered() {
+        final ImmutableOffsetMap<String, String> source = unorderedMap();
+        final MutableOffsetMap<String, String> mutable = source.toModifiableMap();
+
+        mutable.remove("k1");
+        mutable.put("k1", "v1");
+
+        final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
+                .toUnmodifiableMap();
         assertEquals(source, result);
 
         // Only offsets should be shared
@@ -333,7 +379,7 @@ public class OffsetMapTest {
 
     @Test
     public void testEmptyMutable() throws CloneNotSupportedException {
-        final MutableOffsetMap<String, String> map = new MutableOffsetMap<>();
+        final MutableOffsetMap<String, String> map = MutableOffsetMap.ordered();
         assertTrue(map.isEmpty());
 
         final Map<String, String> other = map.clone();
@@ -341,15 +387,6 @@ public class OffsetMapTest {
         assertNotSame(other, map);
     }
 
-    @Test
-    public void testMutableWithKeyset() {
-        final MutableOffsetMap<String, String> map = new MutableOffsetMap<>(ImmutableSet.of("k1", "k2"));
-        assertTrue(map.isEmpty());
-        assertTrue(map.keySet().isEmpty());
-        assertNull(map.get("k1"));
-        assertNull(map.remove("k2"));
-    }
-
     @Test
     public void testMutableToEmpty() {
         final MutableOffsetMap<String, String> mutable = createMap().toModifiableMap();
@@ -370,7 +407,7 @@ public class OffsetMapTest {
         final Map<String, String> result = mutable.toUnmodifiableMap();
 
         // Should devolve to a singleton
-        assertTrue(result instanceof ImmutableMap);
+        assertTrue(result instanceof SharedSingletonMap);
         assertEquals(ImmutableMap.of("k2", "v2"), result);
     }
 
@@ -408,6 +445,24 @@ public class OffsetMapTest {
         mutable.put("k3", "v3");
         mutable.put("k1", "v1");
 
+        assertEquals(ImmutableMap.of("k1", "v1", "k3", "v3"), mutable.newKeys());
+
+        final Map<String, String> result = mutable.toUnmodifiableMap();
+
+        assertTrue(result instanceof ImmutableOffsetMap);
+        assertEquals(threeEntryMap, result);
+        assertEquals(result, threeEntryMap);
+        assertFalse(Iterators.elementsEqual(threeEntryMap.entrySet().iterator(), result.entrySet().iterator()));
+    }
+
+    @Test
+    public void testExpansionWithoutOrder() {
+        final MutableOffsetMap<String, String> mutable = unorderedMap().toModifiableMap();
+
+        mutable.remove("k1");
+        mutable.put("k3", "v3");
+        mutable.put("k1", "v1");
+
         assertEquals(ImmutableMap.of("k3", "v3"), mutable.newKeys());
 
         final Map<String, String> result = mutable.toUnmodifiableMap();
@@ -425,7 +480,8 @@ public class OffsetMapTest {
 
         mutable.put("k1", "replaced");
 
-        final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable.toUnmodifiableMap();
+        final ImmutableOffsetMap<String, String> result = (ImmutableOffsetMap<String, String>) mutable
+                .toUnmodifiableMap();
         final Map<String, String> reference = ImmutableMap.of("k1", "replaced", "k2", "v2");
 
         assertEquals(reference, result);
@@ -460,8 +516,44 @@ public class OffsetMapTest {
         assertFalse(source.needClone());
         assertTrue(result.needClone());
 
+        // Forced copy, no cloning needed, but maps are equal
+        final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source
+                .toUnmodifiableMap();
+        assertFalse(source.needClone());
+        assertTrue(source.equals(immutable));
+        assertTrue(immutable.equals(source));
+        assertTrue(Iterables.elementsEqual(source.entrySet(), immutable.entrySet()));
+    }
+
+    @Test
+    public void testCloneableFlippingUnordered() throws CloneNotSupportedException {
+        final MutableOffsetMap<String, String> source = unorderedMap().toModifiableMap();
+
+        // Must clone before mutation
+        assertTrue(source.needClone());
+
+        // Non-existent entry, should not clone
+        source.remove("non-existent");
+        assertTrue(source.needClone());
+
+        // Changes the array, should clone
+        source.remove("k1");
+        assertFalse(source.needClone());
+
+        // Create a clone of the map, which shares the array
+        final MutableOffsetMap<String, String> result = source.clone();
+        assertFalse(source.needClone());
+        assertTrue(result.needClone());
+        assertSame(source.array(), result.array());
+
+        // Changes the array, should clone
+        source.put("k1", "v2");
+        assertFalse(source.needClone());
+        assertTrue(result.needClone());
+
         // Creates a immutable view, which shares the array
-        final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source.toUnmodifiableMap();
+        final ImmutableOffsetMap<String, String> immutable = (ImmutableOffsetMap<String, String>) source
+                .toUnmodifiableMap();
         assertTrue(source.needClone());
         assertSame(source.array(), immutable.objects());
     }
@@ -494,16 +586,19 @@ public class OffsetMapTest {
             it.hasNext();
             fail();
         } catch (ConcurrentModificationException e) {
+            // OK
         }
         try {
             it.next();
             fail();
         } catch (ConcurrentModificationException e) {
+            // OK
         }
         try {
             it.remove();
             fail();
         } catch (ConcurrentModificationException e) {
+            // OK
         }
     }
 
@@ -535,6 +630,7 @@ public class OffsetMapTest {
             it.remove();
             fail();
         } catch (IllegalStateException e) {
+            // OK
         }
 
         assertTrue(it.hasNext());
@@ -548,6 +644,7 @@ public class OffsetMapTest {
             it.next();
             fail();
         } catch (NoSuchElementException e) {
+            // OK
         }
     }
 
@@ -658,7 +755,7 @@ public class OffsetMapTest {
         final Map<String, String> source = createMap();
 
         final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        try (final ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+        try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
             oos.writeObject(source);
         }