/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.util; import static junit.framework.Assert.fail; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import org.mule.tck.junit4.AbstractMuleTestCase; import org.mule.tck.size.SmallTest; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import org.apache.commons.lang.SerializationUtils; import org.junit.Test; @SuppressWarnings("unchecked") @SmallTest public class CopyOnWriteCaseInsensitiveMapTestCase extends AbstractMuleTestCase { private static final String KEY1 = "FOO"; private static final String KEY2 = "doo"; @Test public void caseInsensitive() throws Exception { assertMapContents(createTestMap()); } @Test public void keysCaseSensitive() throws Exception { Map<String, Object> map = createTestMap(); assertEquals(2, map.keySet().size()); assertTrue(map.keySet().toArray()[0].equals("FOO") || map.keySet().toArray()[0].equals("doo")); assertTrue(map.keySet().toArray()[1].equals("FOO") || map.keySet().toArray()[1].equals("doo")); } @Test public void caseInsensitiveDelegate() throws Exception { assertMapContents(createTestMap().clone()); } @Test public void caseInsensitiveCopiedDelegate() throws Exception { Map<String, Object> map = createTestMap().clone(); map.put("new", "val"); assertMapContents(map); } @Test public void serialize() throws Exception { assertMapContents(serializeAndDeserialize(createTestMap())); } @Test public void serializeDelegate() throws Exception { assertMapContents(serializeAndDeserialize(createTestMap().clone())); } @Test public void serializeCopiedDelegate() throws Exception { Map<String, Object> map = createTestMap().clone(); map.put("new", "val"); assertMapContents(serializeAndDeserialize(map)); } protected Map<String, Object> serializeAndDeserialize(Map<String, Object> map) { byte[] bytes = SerializationUtils.serialize((Serializable) map); return (Map) SerializationUtils.deserialize(bytes); } /* * Assert that Map created with createTestMap() has both of the original properties (FOO and DOO) and that these can be accessed * using case-insensitive keys */ protected void assertMapContents(Map<String, Object> map) { assertEquals("BAR", map.get("FOO")); assertEquals("BAR", map.get("foo")); assertEquals("BAR", map.get("Foo")); assertEquals(Integer.valueOf(3), map.get("DOO")); assertEquals(Integer.valueOf(3), map.get("doo")); assertEquals(Integer.valueOf(3), map.get("Doo")); } /* * Create a CopyOnWriteCaseInsensitiveMap with two properties: F00=BAR (String) and DOO=3 (int). */ protected CopyOnWriteCaseInsensitiveMap<String, Object> createTestMap() { CopyOnWriteCaseInsensitiveMap<String, Object> map = new CopyOnWriteCaseInsensitiveMap<String, Object>(); map.put(KEY1, "BAR"); map.put(KEY2, Integer.valueOf(3)); return map; } @Test public void entrySet() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); assertEquals(2, original.size()); original.keySet().remove("FOO"); assertEquals(1, original.size()); original.keySet().clear(); assertEquals(0, original.size()); } @Test public void entrySetCloneMutateOriginal() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = original.clone(); assertEquals(2, original.size()); assertEquals(2, copyOnWriteMap.size()); original.keySet().remove("FOO"); assertEquals(1, original.size()); assertEquals(2, copyOnWriteMap.size()); original.keySet().clear(); assertEquals(0, original.size()); assertEquals(2, copyOnWriteMap.size()); } @Test public void entrySetCloneMutateClone() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = original.clone(); assertEquals(2, original.size()); assertEquals(2, copyOnWriteMap.size()); copyOnWriteMap.keySet().remove("FOO"); assertEquals(2, original.size()); assertEquals(1, copyOnWriteMap.size()); copyOnWriteMap.keySet().clear(); assertEquals(2, original.size()); assertEquals(0, copyOnWriteMap.size()); } @Test public void putClone() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = original.clone(); original.put("newOriginal", "val"); copyOnWriteMap.put("newCopy", "val"); // Assert state of original map assertMapContents(original); assertEquals(3, original.size()); assertFalse(original.containsKey("newCopy")); assertTrue(original.containsKey("newOriginal")); // Assert state of copy on write map assertMapContents(copyOnWriteMap); assertEquals(3, copyOnWriteMap.size()); assertTrue(copyOnWriteMap.containsKey("newCopy")); assertFalse(copyOnWriteMap.containsKey("newOriginal")); } @Test public void putAllClone() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = original.clone(); Map<String, String> newOriginalEntriesMap = new HashMap<String, String>(); newOriginalEntriesMap.put("newOriginal1", "val"); newOriginalEntriesMap.put("newOriginal2", "val"); newOriginalEntriesMap.put("newOriginal3", "val"); original.putAll(newOriginalEntriesMap); Map<String, String> newCopyEntriesMap = new HashMap<String, String>(); newCopyEntriesMap.put("newCopy1", "val"); newCopyEntriesMap.put("newCopy2", "val"); newCopyEntriesMap.put("newCopy3", "val"); copyOnWriteMap.putAll(newCopyEntriesMap); // Assert state of original map assertMapContents(original); assertEquals(5, original.size()); assertTrue(original.containsKey("newOriginal1")); assertTrue(original.containsKey("newOriginal2")); assertTrue(original.containsKey("newOriginal3")); assertFalse(original.containsKey("newCopy1")); assertFalse(original.containsKey("newCopy2")); assertFalse(original.containsKey("newCopy3")); // Assert state of copy on write map assertMapContents(copyOnWriteMap); assertEquals(5, copyOnWriteMap.size()); assertTrue(copyOnWriteMap.containsKey("newCopy1")); assertTrue(copyOnWriteMap.containsKey("newCopy2")); assertTrue(copyOnWriteMap.containsKey("newCopy3")); assertFalse(copyOnWriteMap.containsKey("newOriginal1")); assertFalse(copyOnWriteMap.containsKey("newOriginal2")); assertFalse(copyOnWriteMap.containsKey("newOriginal3")); } @Test public void removeClone() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); original.put("extra", "value"); original.put("extra2", "value"); Map<String, Object> copyOnWriteMap = original.clone(); original.remove("extra"); copyOnWriteMap.remove("extra2"); // Assert state of original map assertMapContents(original); assertEquals(3, original.size()); assertFalse(original.containsKey("extra")); assertTrue(original.containsKey("extra2")); // Assert state of copy on write map assertMapContents(copyOnWriteMap); assertEquals(3, copyOnWriteMap.size()); assertTrue(copyOnWriteMap.containsKey("extra")); assertFalse(copyOnWriteMap.containsKey("extra2")); } @Test public void clearOrignalClone() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = original.clone(); original.clear(); assertEquals(0, original.size()); assertEquals(0, original.entrySet().size()); assertEquals(2, copyOnWriteMap.size()); assertEquals(2, copyOnWriteMap.entrySet().size()); } @Test public void clearCopyClone() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = original.clone(); copyOnWriteMap.clear(); assertEquals(2, original.size()); assertEquals(2, original.entrySet().size()); assertEquals(0, copyOnWriteMap.size()); assertEquals(0, copyOnWriteMap.entrySet().size()); } @Test public void entrySetDeserializedMutateOriginal() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = serializeAndDeserialize(original); assertEquals(2, original.size()); assertEquals(2, copyOnWriteMap.size()); original.keySet().remove("FOO"); assertEquals(1, original.size()); assertEquals(2, copyOnWriteMap.size()); original.keySet().clear(); assertEquals(0, original.size()); assertEquals(2, copyOnWriteMap.size()); } @Test public void entrySetDeserializedMutateClone() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = serializeAndDeserialize(original); assertEquals(2, original.size()); assertEquals(2, copyOnWriteMap.size()); copyOnWriteMap.keySet().remove("FOO"); assertEquals(2, original.size()); assertEquals(1, copyOnWriteMap.size()); copyOnWriteMap.keySet().clear(); assertEquals(2, original.size()); assertEquals(0, copyOnWriteMap.size()); } @Test public void putDeserialized() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = serializeAndDeserialize(original); original.put("newOriginal", "val"); copyOnWriteMap.put("newCopy", "val"); // Assert state of original map assertMapContents(original); assertEquals(3, original.size()); assertFalse(original.containsKey("newCopy")); assertTrue(original.containsKey("newOriginal")); // Assert state of copy on write map assertMapContents(copyOnWriteMap); assertEquals(3, copyOnWriteMap.size()); assertTrue(copyOnWriteMap.containsKey("newCopy")); assertFalse(copyOnWriteMap.containsKey("newOriginal")); } @Test public void putAllDeserialized() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = serializeAndDeserialize(original); Map<String, String> newOriginalEntriesMap = new HashMap<String, String>(); newOriginalEntriesMap.put("newOriginal1", "val"); newOriginalEntriesMap.put("newOriginal2", "val"); newOriginalEntriesMap.put("newOriginal3", "val"); original.putAll(newOriginalEntriesMap); Map<String, String> newCopyEntriesMap = new HashMap<String, String>(); newCopyEntriesMap.put("newCopy1", "val"); newCopyEntriesMap.put("newCopy2", "val"); newCopyEntriesMap.put("newCopy3", "val"); copyOnWriteMap.putAll(newCopyEntriesMap); // Assert state of original map assertMapContents(original); assertEquals(5, original.size()); assertTrue(original.containsKey("newOriginal1")); assertTrue(original.containsKey("newOriginal2")); assertTrue(original.containsKey("newOriginal3")); assertFalse(original.containsKey("newCopy1")); assertFalse(original.containsKey("newCopy2")); assertFalse(original.containsKey("newCopy3")); // Assert state of copy on write map assertMapContents(copyOnWriteMap); assertEquals(5, copyOnWriteMap.size()); assertTrue(copyOnWriteMap.containsKey("newCopy1")); assertTrue(copyOnWriteMap.containsKey("newCopy2")); assertTrue(copyOnWriteMap.containsKey("newCopy3")); assertFalse(copyOnWriteMap.containsKey("newOriginal1")); assertFalse(copyOnWriteMap.containsKey("newOriginal2")); assertFalse(copyOnWriteMap.containsKey("newOriginal3")); } @Test public void removeDeserialized() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); original.put("extra", "value"); original.put("extra2", "value"); Map<String, Object> copyOnWriteMap = serializeAndDeserialize(original); original.remove("extra"); copyOnWriteMap.remove("extra2"); // Assert state of original map assertMapContents(original); assertEquals(3, original.size()); assertFalse(original.containsKey("extra")); assertTrue(original.containsKey("extra2")); // Assert state of copy on write map assertMapContents(copyOnWriteMap); assertEquals(3, copyOnWriteMap.size()); assertTrue(copyOnWriteMap.containsKey("extra")); assertFalse(copyOnWriteMap.containsKey("extra2")); } @Test public void clearOrignalDeserialized() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = serializeAndDeserialize(original); original.clear(); assertEquals(0, original.size()); assertEquals(0, original.entrySet().size()); assertEquals(2, copyOnWriteMap.size()); assertEquals(2, copyOnWriteMap.entrySet().size()); } @Test public void clearCopyDeserialized() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> original = createTestMap(); Map<String, Object> copyOnWriteMap = serializeAndDeserialize(original); copyOnWriteMap.clear(); assertEquals(2, original.size()); assertEquals(2, original.entrySet().size()); assertEquals(0, copyOnWriteMap.size()); assertEquals(0, copyOnWriteMap.entrySet().size()); } @Test public void keySetGivesAllKeys() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> map = createTestMap(); Set<String> foundKeys = new HashSet<String>(); for (String key : map.keySet()) { assertTrue(KEY1.equals(key) || KEY2.equals(key)); assertFalse(foundKeys.contains(key)); foundKeys.add(key); } } @Test public void removeKeySetItem() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> map = createTestMap(); Iterator<String> it = map.keySet().iterator(); assertTrue(it.hasNext()); String key = it.next(); it.remove(); assertFalse(map.keySet().contains(key)); it = map.keySet().iterator(); assertTrue(it.hasNext()); String key2 = it.next(); assertFalse(key.equals(key2)); assertFalse(it.hasNext()); it.remove(); assertFalse(it.hasNext()); assertTrue(map.keySet().isEmpty()); it = map.keySet().iterator(); assertFalse(it.hasNext()); try { it.next(); fail("Was expecting NoSuchElementException"); } catch (NoSuchElementException e) { // happyness } } @Test(expected = NoSuchElementException.class) public void emptyMapKeySetIterator() throws Exception { Map<String, String> map = new CopyOnWriteCaseInsensitiveMap<String, String>(); assertTrue(map.keySet().isEmpty()); Iterator<String> iterator = map.keySet().iterator(); assertFalse(iterator.hasNext()); iterator.next(); } @Test(expected = IllegalStateException.class) public void removeInKeySetIteratorBeforeAnyNext() throws Exception { createTestMap().keySet().iterator().remove(); } @Test(expected = IllegalStateException.class) public void keySetIteratorWithTwoRemovesInTheSameNext() throws Exception { Iterator<String> iterator = createTestMap().keySet().iterator(); iterator.next(); iterator.remove(); iterator.remove(); } @Test public void removeShouldNotMoveForward() throws Exception { CopyOnWriteCaseInsensitiveMap<String, Object> map = createTestMap(); // add a third element to spice things up final String EXTRA_KEY = "THIRD"; map.put(EXTRA_KEY, new Object()); // store iteration order List<String> keys = new ArrayList<String>(); for (String key : map.keySet()) { keys.add(key); } // now remove second element and make sure that the next element is the third Iterator<String> iterator = map.keySet().iterator(); iterator.next(); iterator.next(); iterator.remove(); String key = iterator.next(); assertEquals(keys.get(2), key); assertFalse(iterator.hasNext()); } @Test public void asHashMap() { CopyOnWriteCaseInsensitiveMap<String, Object> map = createTestMap(); Map<String, Object> regularMap = map.asHashMap(); assertThat(regularMap, is(instanceOf(HashMap.class))); assertThat(regularMap.size(), is(map.size())); for (Map.Entry<String, Object> entry : map.entrySet()) { assertThat(map.get(entry.getKey()), is(regularMap.get(entry.getKey()))); } } }