You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/09/24 13:38:02 UTC
logging-log4j2 git commit: LOG4J2-1611 productionize
JdkMapAdapterStringMap (null checks, toString/equals/hashCode); allow mutation;
add unit tests
Repository: logging-log4j2
Updated Branches:
refs/heads/master e1902e97f -> d16716a58
LOG4J2-1611 productionize JdkMapAdapterStringMap (null checks, toString/equals/hashCode); allow mutation; add unit tests
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d16716a5
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d16716a5
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d16716a5
Branch: refs/heads/master
Commit: d16716a58e6bba87f7874f23dfc43db41edbf1b6
Parents: e1902e9
Author: rpopma <rp...@apache.org>
Authored: Sat Sep 24 22:37:53 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sat Sep 24 22:37:53 2016 +0900
----------------------------------------------------------------------
.../log4j/core/impl/JdkMapAdapterStringMap.java | 69 +-
.../core/impl/JdkMapAdapterStringMapTest.java | 882 +++++++++++++++++++
2 files changed, 942 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d16716a5/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
index b9387b9a..504b194 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
@@ -16,7 +16,9 @@
*/
package org.apache.logging.log4j.core.impl;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import org.apache.logging.log4j.util.BiConsumer;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
@@ -28,10 +30,17 @@ import org.apache.logging.log4j.util.TriConsumer;
*/
class JdkMapAdapterStringMap implements StringMap {
private static final long serialVersionUID = -7348247784983193612L;
- private Map<String, String> map;
+ private static final String FROZEN = "Frozen collection cannot be modified";
+
+ private final Map<String, String> map;
+ private boolean immutable = false;
+
+ public JdkMapAdapterStringMap() {
+ this(new HashMap<String, String>());
+ }
public JdkMapAdapterStringMap(final Map<String, String> map) {
- this.map = map;
+ this.map = Objects.requireNonNull(map, "map");
}
@Override
@@ -39,6 +48,12 @@ class JdkMapAdapterStringMap implements StringMap {
return map;
}
+ private void assertNotFrozen() {
+ if (immutable) {
+ throw new UnsupportedOperationException(FROZEN);
+ }
+ }
+
@Override
public boolean containsKey(final String key) {
return map.containsKey(key);
@@ -78,34 +93,70 @@ class JdkMapAdapterStringMap implements StringMap {
@Override
public void clear() {
- fail();
+ if (map.isEmpty()) {
+ return;
+ }
+ assertNotFrozen();
+ map.clear();
}
@Override
public void freeze() {
+ immutable = true;
}
@Override
public boolean isFrozen() {
- return true;
+ return immutable;
}
@Override
public void putAll(final ReadOnlyStringMap source) {
- fail();
+ assertNotFrozen();
+ source.forEach(PUT_ALL, map);
}
+ private static TriConsumer<String, String, Map<String, String>> PUT_ALL = new TriConsumer<String, String, Map<String, String>>() {
+ @Override
+ public void accept(final String key, final String value, final Map<String, String> stringStringMap) {
+ stringStringMap.put(key, value);
+ }
+ };
+
@Override
public void putValue(final String key, final Object value) {
- fail();
+ assertNotFrozen();
+ map.put(key, value == null ? null : String.valueOf(value));
}
@Override
public void remove(final String key) {
- fail();
+ if (!map.containsKey(key)) {
+ return;
+ }
+ assertNotFrozen();
+ map.remove(key);
}
- private void fail() {
- throw new UnsupportedOperationException("This is a read-only data structure");
+ @Override
+ public String toString() {
+ return map.toString();
+ }
+
+ @Override
+ public boolean equals(final Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof JdkMapAdapterStringMap)) {
+ return false;
+ }
+ JdkMapAdapterStringMap other = (JdkMapAdapterStringMap) object;
+ return map.equals(other.map) && immutable == other.immutable;
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode() + (immutable ? 31 : 0);
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d16716a5/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java
new file mode 100644
index 0000000..482d399
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java
@@ -0,0 +1,882 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.logging.log4j.util.BiConsumer;
+import org.apache.logging.log4j.util.TriConsumer;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests the JdkMapAdapterStringMap class.
+ */
+public class JdkMapAdapterStringMapTest {
+
+ @Test(expected = NullPointerException.class)
+ public void testConstructorDisallowsNull() throws Exception {
+ new JdkMapAdapterStringMap(null);
+ }
+
+ @Test
+ public void testToString() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+ assertEquals("{3=3value, B=Bvalue, a=avalue}", original.toString());
+ }
+
+ @Test
+ public void testSerialization() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+
+ final byte[] binary = serialize(original);
+ final JdkMapAdapterStringMap copy = deserialize(binary);
+ assertEquals(original, copy);
+ }
+
+ private byte[] serialize(final JdkMapAdapterStringMap data) throws IOException {
+ final ByteArrayOutputStream arr = new ByteArrayOutputStream();
+ final ObjectOutputStream out = new ObjectOutputStream(arr);
+ out.writeObject(data);
+ return arr.toByteArray();
+ }
+
+ private JdkMapAdapterStringMap deserialize(final byte[] binary) throws IOException, ClassNotFoundException {
+ final ByteArrayInputStream inArr = new ByteArrayInputStream(binary);
+ final ObjectInputStream in = new ObjectInputStream(inArr);
+ final JdkMapAdapterStringMap result = (JdkMapAdapterStringMap) in.readObject();
+ return result;
+ }
+
+ @Test
+ public void testPutAll() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putAll(original);
+ assertEquals(original, other);
+
+ other.putValue("3", "otherValue");
+ assertNotEquals(original, other);
+
+ other.putValue("3", null);
+ assertNotEquals(original, other);
+
+ other.putValue("3", "3value");
+ assertEquals(original, other);
+ }
+
+ @Test
+ public void testPutAll_overwritesSameKeys2() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+ original.putValue("c", "cORIG");
+ original.putValue("d", "dORIG");
+ original.putValue("e", "eORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue("1", "11");
+ other.putValue("2", "22");
+ other.putValue("a", "aa");
+ other.putValue("c", "cc");
+ original.putAll(other);
+
+ assertEquals("size after put other", 7, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("cc", original.getValue("c"));
+ assertEquals("dORIG", original.getValue("d"));
+ assertEquals("eORIG", original.getValue("e"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("22", original.getValue("2"));
+ }
+
+ @Test
+ public void testPutAll_nullKeyInLargeOriginal() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue(null, "nullORIG");
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+ original.putValue("c", "cORIG");
+ original.putValue("d", "dORIG");
+ original.putValue("e", "eORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue("1", "11");
+ other.putValue("a", "aa");
+ original.putAll(other);
+
+ assertEquals("size after put other", 7, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("cORIG", original.getValue("c"));
+ assertEquals("dORIG", original.getValue("d"));
+ assertEquals("eORIG", original.getValue("e"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("nullORIG", original.getValue(null));
+ }
+
+ @Test
+ public void testPutAll_nullKeyInSmallOriginal() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue(null, "nullORIG");
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue("1", "11");
+ other.putValue("2", "22");
+ other.putValue("3", "33");
+ other.putValue("a", "aa");
+ original.putAll(other);
+
+ assertEquals("size after put other", 6, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("22", original.getValue("2"));
+ assertEquals("33", original.getValue("3"));
+ assertEquals("nullORIG", original.getValue(null));
+ }
+
+ @Test
+ public void testPutAll_nullKeyInSmallAdditional() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+ original.putValue("c", "cORIG");
+ original.putValue("d", "dORIG");
+ original.putValue("e", "eORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue(null, "nullNEW");
+ other.putValue("1", "11");
+ other.putValue("a", "aa");
+ original.putAll(other);
+
+ assertEquals("size after put other", 7, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("cORIG", original.getValue("c"));
+ assertEquals("dORIG", original.getValue("d"));
+ assertEquals("eORIG", original.getValue("e"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("nullNEW", original.getValue(null));
+ }
+
+ @Test
+ public void testPutAll_nullKeyInLargeAdditional() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue(null, "nullNEW");
+ other.putValue("1", "11");
+ other.putValue("2", "22");
+ other.putValue("3", "33");
+ other.putValue("a", "aa");
+ original.putAll(other);
+
+ assertEquals("size after put other", 6, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("22", original.getValue("2"));
+ assertEquals("33", original.getValue("3"));
+ assertEquals("nullNEW", original.getValue(null));
+ }
+
+ @Test
+ public void testPutAll_nullKeyInBoth_LargeOriginal() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue(null, "nullORIG");
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+ original.putValue("c", "cORIG");
+ original.putValue("d", "dORIG");
+ original.putValue("e", "eORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue(null, "nullNEW");
+ other.putValue("1", "11");
+ other.putValue("a", "aa");
+ original.putAll(other);
+
+ assertEquals("size after put other", 7, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("cORIG", original.getValue("c"));
+ assertEquals("dORIG", original.getValue("d"));
+ assertEquals("eORIG", original.getValue("e"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("nullNEW", original.getValue(null));
+ }
+
+ @Test
+ public void testPutAll_nullKeyInBoth_SmallOriginal() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue(null, "nullORIG");
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue(null, "nullNEW");
+ other.putValue("1", "11");
+ other.putValue("2", "22");
+ other.putValue("3", "33");
+ other.putValue("a", "aa");
+ original.putAll(other);
+
+ assertEquals("size after put other", 6, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("22", original.getValue("2"));
+ assertEquals("33", original.getValue("3"));
+ assertEquals("nullNEW", original.getValue(null));
+ }
+
+ @Test
+ public void testPutAll_overwritesSameKeys1() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aORIG");
+ original.putValue("b", "bORIG");
+ original.putValue("c", "cORIG");
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue("1", "11");
+ other.putValue("2", "22");
+ other.putValue("a", "aa");
+ other.putValue("c", "cc");
+ original.putAll(other);
+
+ assertEquals("size after put other", 5, original.size());
+ assertEquals("aa", original.getValue("a"));
+ assertEquals("bORIG", original.getValue("b"));
+ assertEquals("cc", original.getValue("c"));
+ assertEquals("11", original.getValue("1"));
+ assertEquals("22", original.getValue("2"));
+ }
+
+ @Test
+ public void testEquals() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+ assertEquals(original, original); // equal to itself
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue("a", "avalue");
+ assertNotEquals(original, other);
+
+ other.putValue("B", "Bvalue");
+ assertNotEquals(original, other);
+
+ other.putValue("3", "3value");
+ assertEquals(original, other);
+
+ other.putValue("3", "otherValue");
+ assertNotEquals(original, other);
+
+ other.putValue("3", null);
+ assertNotEquals(original, other);
+
+ other.putValue("3", "3value");
+ assertEquals(original, other);
+ }
+
+ @Test
+ public void testToMap() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+
+ final Map<String, Object> expected = new HashMap<>();
+ expected.put("a", "avalue");
+ expected.put("B", "Bvalue");
+ expected.put("3", "3value");
+
+ assertEquals(expected, original.toMap());
+
+ try {
+ original.toMap().put("abc", "xyz");
+ } catch (final UnsupportedOperationException ex) {
+ fail("Expected map to be mutable, but " + ex);
+ }
+ }
+
+ @Test
+ public void testPutAll_KeepsExistingValues() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "bbb");
+ original.putValue("c", "ccc");
+ assertEquals("size", 3, original.size());
+
+ // add empty context data
+ original.putAll(new JdkMapAdapterStringMap());
+ assertEquals("size after put empty", 3, original.size());
+ assertEquals("aaa", original.getValue("a"));
+ assertEquals("bbb", original.getValue("b"));
+ assertEquals("ccc", original.getValue("c"));
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue("1", "111");
+ other.putValue("2", "222");
+ other.putValue("3", "333");
+ original.putAll(other);
+
+ assertEquals("size after put other", 6, original.size());
+ assertEquals("aaa", original.getValue("a"));
+ assertEquals("bbb", original.getValue("b"));
+ assertEquals("ccc", original.getValue("c"));
+ assertEquals("111", original.getValue("1"));
+ assertEquals("222", original.getValue("2"));
+ assertEquals("333", original.getValue("3"));
+ }
+
+ @Test
+ public void testPutAll_sizePowerOfTwo() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "bbb");
+ original.putValue("c", "ccc");
+ original.putValue("d", "ddd");
+ assertEquals("size", 4, original.size());
+
+ // add empty context data
+ original.putAll(new JdkMapAdapterStringMap());
+ assertEquals("size after put empty", 4, original.size());
+ assertEquals("aaa", original.getValue("a"));
+ assertEquals("bbb", original.getValue("b"));
+ assertEquals("ccc", original.getValue("c"));
+ assertEquals("ddd", original.getValue("d"));
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ other.putValue("1", "111");
+ other.putValue("2", "222");
+ other.putValue("3", "333");
+ other.putValue("4", "444");
+ original.putAll(other);
+
+ assertEquals("size after put other", 8, original.size());
+ assertEquals("aaa", original.getValue("a"));
+ assertEquals("bbb", original.getValue("b"));
+ assertEquals("ccc", original.getValue("c"));
+ assertEquals("ddd", original.getValue("d"));
+ assertEquals("111", original.getValue("1"));
+ assertEquals("222", original.getValue("2"));
+ assertEquals("333", original.getValue("3"));
+ assertEquals("444", original.getValue("4"));
+ }
+
+ @Test
+ public void testPutAll_largeAddition() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue(null, "nullVal");
+ original.putValue("a", "aaa");
+ original.putValue("b", "bbb");
+ original.putValue("c", "ccc");
+ original.putValue("d", "ddd");
+ assertEquals("size", 5, original.size());
+
+ final JdkMapAdapterStringMap other = new JdkMapAdapterStringMap();
+ for (int i = 0 ; i < 500; i++) {
+ other.putValue(String.valueOf(i), String.valueOf(i));
+ }
+ other.putValue(null, "otherVal");
+ original.putAll(other);
+
+ assertEquals("size after put other", 505, original.size());
+ assertEquals("otherVal", original.getValue(null));
+ assertEquals("aaa", original.getValue("a"));
+ assertEquals("bbb", original.getValue("b"));
+ assertEquals("ccc", original.getValue("c"));
+ assertEquals("ddd", original.getValue("d"));
+ for (int i = 0 ; i < 500; i++) {
+ assertEquals(String.valueOf(i), original.getValue(String.valueOf(i)));
+ }
+ }
+
+ @Test
+ public void testPutAllSelfDoesNotModify() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "bbb");
+ original.putValue("c", "ccc");
+ assertEquals("size", 3, original.size());
+
+ // putAll with self
+ original.putAll(original);
+ assertEquals("size after put empty", 3, original.size());
+ assertEquals("aaa", original.getValue("a"));
+ assertEquals("bbb", original.getValue("b"));
+ assertEquals("ccc", original.getValue("c"));
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerPut() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("c", "aaa");
+ original.putValue("d", "aaa");
+ original.putValue("e", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.putValue("c" + s, "other");
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerPutValue() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("c", "aaa");
+ original.putValue("d", "aaa");
+ original.putValue("e", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.putValue("c" + s, "other");
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerRemove() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("c", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.remove("a");
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerClear() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("c", "aaa");
+ original.putValue("d", "aaa");
+ original.putValue("e", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.clear();
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerPut() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("d", "aaa");
+ original.putValue("e", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.putValue("c", "other");
+ }
+ }, null);
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerPutValue() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("c", "aaa");
+ original.putValue("d", "aaa");
+ original.putValue("e", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.putValue("c" + s, "other");
+ }
+ }, null);
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerRemove() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("c", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.remove("a");
+ }
+ }, null);
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerClear() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.putValue("b", "aaa");
+ original.putValue("c", "aaa");
+ original.putValue("d", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.clear();
+ }
+ }, null);
+ }
+
+ @Test
+ public void testInitiallyNotFrozen() {
+ assertFalse(new JdkMapAdapterStringMap().isFrozen());
+ }
+
+ @Test
+ public void testIsFrozenAfterCallingFreeze() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ assertFalse("before freeze", original.isFrozen());
+ original.freeze();
+ assertTrue("after freeze", original.isFrozen());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFreezeProhibitsPutValue() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.freeze();
+ original.putValue("a", "aaa");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFreezeProhibitsRemove() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("b", "bbb");
+ original.freeze();
+ original.remove("b"); // existing key: modifies the collection
+ }
+
+ @Test
+ public void testFreezeAllowsRemoveOfNonExistingKey() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("b", "bbb");
+ original.freeze();
+ original.remove("a"); // no actual modification
+ }
+
+ @Test
+ public void testFreezeAllowsRemoveIfEmpty() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.freeze();
+ original.remove("a"); // no exception
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFreezeProhibitsClear() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "aaa");
+ original.freeze();
+ original.clear();
+ }
+
+ @Test
+ public void testFreezeAllowsClearIfEmpty() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.freeze();
+ original.clear();
+ }
+
+ @Test
+ public void testNullKeysAllowed() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+ original.putValue("c", "cvalue");
+ original.putValue("d", "dvalue");
+ assertEquals(5, original.size());
+
+ original.putValue(null, "nullvalue");
+ assertEquals(6, original.size());
+ assertEquals("nullvalue", original.getValue(null));
+
+ original.putValue(null, "otherNullvalue");
+ assertEquals("otherNullvalue", original.getValue(null));
+ assertEquals(6, original.size());
+
+ original.putValue(null, "nullvalue");
+ assertEquals(6, original.size());
+ assertEquals("nullvalue", original.getValue(null));
+
+ original.putValue(null, "abc");
+ assertEquals(6, original.size());
+ assertEquals("abc", original.getValue(null));
+
+ }
+
+ @Test
+ public void testNullKeysCopiedToAsMap() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+ original.putValue("c", "cvalue");
+ original.putValue("d", "dvalue");
+ assertEquals(5, original.size());
+
+ final HashMap<String, String> expected = new HashMap<>();
+ expected.put("a", "avalue");
+ expected.put("B", "Bvalue");
+ expected.put("3", "3value");
+ expected.put("c", "cvalue");
+ expected.put("d", "dvalue");
+ assertEquals("initial", expected, original.toMap());
+
+ original.putValue(null, "nullvalue");
+ expected.put(null, "nullvalue");
+ assertEquals(6, original.size());
+ assertEquals("with null key", expected, original.toMap());
+
+ original.putValue(null, "otherNullvalue");
+ expected.put(null, "otherNullvalue");
+ assertEquals(6, original.size());
+ assertEquals("with null key value2", expected, original.toMap());
+
+ original.putValue(null, "nullvalue");
+ expected.put(null, "nullvalue");
+ assertEquals(6, original.size());
+ assertEquals("with null key value1 again", expected, original.toMap());
+
+ original.putValue(null, "abc");
+ expected.put(null, "abc");
+ assertEquals(6, original.size());
+ assertEquals("with null key value3", expected, original.toMap());
+ }
+
+ @Test
+ public void testRemove() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ assertEquals(1, original.size());
+ assertEquals("avalue", original.getValue("a"));
+
+ original.remove("a");
+ assertEquals(0, original.size());
+ assertNull("no a val", original.getValue("a"));
+
+ original.remove("B");
+ assertEquals(0, original.size());
+ assertNull("no B val", original.getValue("B"));
+ }
+
+ @Test
+ public void testRemoveWhenFull() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("b", "bvalue");
+ original.putValue("c", "cvalue");
+ original.putValue("d", "dvalue"); // default capacity = 4
+ original.remove("d");
+ }
+
+ @Test
+ public void testNullValuesArePreserved() {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ assertEquals(1, original.size());
+ assertEquals("avalue", original.getValue("a"));
+
+ original.putValue("a", null);
+ assertEquals(1, original.size());
+ assertNull("no a val", original.getValue("a"));
+
+ original.putValue("B", null);
+ assertEquals(2, original.size());
+ assertNull("no B val", original.getValue("B"));
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+
+ assertEquals("avalue", original.getValue("a"));
+ assertEquals("Bvalue", original.getValue("B"));
+ assertEquals("3value", original.getValue("3"));
+
+ original.putValue("0", "0value");
+ assertEquals("0value", original.getValue("0"));
+ assertEquals("3value", original.getValue("3"));
+ assertEquals("Bvalue", original.getValue("B"));
+ assertEquals("avalue", original.getValue("a"));
+ }
+
+ @Test
+ public void testClear() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+ assertEquals(3, original.size());
+
+ original.clear();
+ assertEquals(0, original.size());
+ }
+
+ @Test
+ public void testContainsKey() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ assertFalse("a", original.containsKey("a"));
+ assertFalse("B", original.containsKey("B"));
+ assertFalse("3", original.containsKey("3"));
+ assertFalse("A", original.containsKey("A"));
+
+ original.putValue("a", "avalue");
+ assertTrue("a", original.containsKey("a"));
+ assertFalse("B", original.containsKey("B"));
+ assertFalse("3", original.containsKey("3"));
+ assertFalse("A", original.containsKey("A"));
+
+ original.putValue("B", "Bvalue");
+ assertTrue("a", original.containsKey("a"));
+ assertTrue("B", original.containsKey("B"));
+ assertFalse("3", original.containsKey("3"));
+ assertFalse("A", original.containsKey("A"));
+
+ original.putValue("3", "3value");
+ assertTrue("a", original.containsKey("a"));
+ assertTrue("B", original.containsKey("B"));
+ assertTrue("3", original.containsKey("3"));
+ assertFalse("A", original.containsKey("A"));
+
+ original.putValue("A", "AAA");
+ assertTrue("a", original.containsKey("a"));
+ assertTrue("B", original.containsKey("B"));
+ assertTrue("3", original.containsKey("3"));
+ assertTrue("A", original.containsKey("A"));
+ }
+
+ @Test
+ public void testSizeAndIsEmpty() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ assertEquals(0, original.size());
+ assertTrue("initial", original.isEmpty());
+
+ original.putValue("a", "avalue");
+ assertEquals(1, original.size());
+ assertFalse("size=" + original.size(), original.isEmpty());
+
+ original.putValue("B", "Bvalue");
+ assertEquals(2, original.size());
+ assertFalse("size=" + original.size(), original.isEmpty());
+
+ original.putValue("3", "3value");
+ assertEquals(3, original.size());
+ assertFalse("size=" + original.size(), original.isEmpty());
+
+ original.remove("B");
+ assertEquals(2, original.size());
+ assertFalse("size=" + original.size(), original.isEmpty());
+
+ original.remove("3");
+ assertEquals(1, original.size());
+ assertFalse("size=" + original.size(), original.isEmpty());
+
+ original.remove("a");
+ assertEquals(0, original.size());
+ assertTrue("size=" + original.size(), original.isEmpty());
+ }
+
+ @Test
+ public void testForEachBiConsumer() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+
+ original.forEach(new BiConsumer<String, String>() {
+ int count = 0;
+ @Override
+ public void accept(final String key, final String value) {
+// assertEquals("key", key, original.getKeyAt(count));
+// assertEquals("val", value, original.getValueAt(count));
+ count++;
+ assertTrue("count should not exceed size but was " + count, count <= original.size());
+ }
+ });
+ }
+
+ static class State {
+ JdkMapAdapterStringMap data;
+ int count;
+ }
+ static TriConsumer<String, String, JdkMapAdapterStringMapTest.State> COUNTER = new TriConsumer<String, String, JdkMapAdapterStringMapTest.State>() {
+ @Override
+ public void accept(final String key, final String value, final JdkMapAdapterStringMapTest.State state) {
+// assertEquals("key", key, state.data.getKeyAt(state.count));
+// assertEquals("val", value, state.data.getValueAt(state.count));
+ state.count++;
+ assertTrue("count should not exceed size but was " + state.count,
+ state.count <= state.data.size());
+ }
+ };
+
+ @Test
+ public void testForEachTriConsumer() throws Exception {
+ final JdkMapAdapterStringMap original = new JdkMapAdapterStringMap();
+ original.putValue("a", "avalue");
+ original.putValue("B", "Bvalue");
+ original.putValue("3", "3value");
+
+ final JdkMapAdapterStringMapTest.State state = new JdkMapAdapterStringMapTest.State();
+ state.data = original;
+ original.forEach(COUNTER, state);
+ assertEquals(state.count, original.size());
+ }
+
+}
\ No newline at end of file