This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git


The following commit(s) were added to refs/heads/master by this push:
     new c96dc7a92 Add AbstractMapTest.testMapComputeIfAbsent()
c96dc7a92 is described below

commit c96dc7a92491913ac7e234de875c505e01cd2ec1
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Wed Sep 25 13:14:12 2024 -0400

    Add AbstractMapTest.testMapComputeIfAbsent()
---
 src/conf/checkstyle.xml                            |   4 -
 .../commons/collections4/map/AbstractMapTest.java  | 158 +++++++++++++++++++--
 2 files changed, 146 insertions(+), 16 deletions(-)

diff --git a/src/conf/checkstyle.xml b/src/conf/checkstyle.xml
index 0b543f10e..ed165f598 100644
--- a/src/conf/checkstyle.xml
+++ b/src/conf/checkstyle.xml
@@ -61,10 +61,6 @@ limitations under the License.
     <module name="WhitespaceAfter"/>
     <module name="WhitespaceAround"/>
     <module name="NoWhitespaceBefore"/>
-    <module name="Indentation">
-      <!-- Indentation style recommended by Oracle -->
-      <property name="caseIndent" value="0"/>
-    </module>
     <module name="ImportOrder">
       <property name="option" value="top"/>
       <property name="groups" value="java,javax,junit,org,com"/>
diff --git 
a/src/test/java/org/apache/commons/collections4/map/AbstractMapTest.java 
b/src/test/java/org/apache/commons/collections4/map/AbstractMapTest.java
index cfd0f5f46..6246b48c2 100644
--- a/src/test/java/org/apache/commons/collections4/map/AbstractMapTest.java
+++ b/src/test/java/org/apache/commons/collections4/map/AbstractMapTest.java
@@ -644,8 +644,8 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
     @SuppressWarnings("unchecked")
     public V[] getNewSampleValues() {
         final Object[] result = { isAllowNullValue() && 
isAllowDuplicateValues() ? null : "newnonnullvalue", "newvalue",
-            isAllowDuplicateValues() ? "newvalue" : "newvalue2", "newblahv", 
"newfoov", "newbarv", "newbazv", "newtmpv", "newgoshv", "newgollyv", "newgeev",
-            "newhellov", "newgoodbyev", "newwe'llv", "newseev", "newyouv", 
"newallv", "newagainv" };
+                isAllowDuplicateValues() ? "newvalue" : "newvalue2", 
"newblahv", "newfoov", "newbarv", "newbazv", "newtmpv", "newgoshv", 
"newgollyv", "newgeev",
+                "newhellov", "newgoodbyev", "newwe'llv", "newseev", "newyouv", 
"newallv", "newagainv" };
         return (V[]) result;
     }
 
@@ -663,7 +663,7 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
      */
     public Object[] getOtherNonNullStringElements() {
         return new Object[] { "For", "then", "despite", /* of */"space", "I", 
"would", "be", "brought", "From", "limits", "far", "remote", "where", "thou",
-            "dost", "stay" };
+                "dost", "stay" };
     }
 
     @SuppressWarnings("unchecked")
@@ -679,7 +679,7 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
     @SuppressWarnings("unchecked")
     public K[] getSampleKeys() {
         final Object[] result = { "blah", "foo", "bar", "baz", "tmp", "gosh", 
"golly", "gee", "hello", "goodbye", "we'll", "see", "you", "all", "again", 
"key",
-            "key2", isAllowNullKey() ? null : "nonnullkey" };
+                "key2", isAllowNullKey() ? null : "nonnullkey" };
         return (K[]) result;
     }
 
@@ -691,7 +691,7 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
     @SuppressWarnings("unchecked")
     public V[] getSampleValues() {
         final Object[] result = { "blahv", "foov", "barv", "bazv", "tmpv", 
"goshv", "gollyv", "geev", "hellov", "goodbyev", "we'llv", "seev", "youv", 
"allv",
-            "againv", isAllowNullValue() ? null : "nonnullvalue", "value", 
isAllowDuplicateValues() ? "value" : "value2", };
+                "againv", isAllowNullValue() ? null : "nonnullvalue", "value", 
isAllowDuplicateValues() ? "value" : "value2", };
         return (V[]) result;
     }
 
@@ -741,6 +741,15 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
         return false;
     }
 
+    protected boolean isLazyMapTest() {
+        return false;
+    }
+
+    // tests begin here. Each test adds a little bit of tested functionality.
+    // Many methods assume previous methods passed. That is, they do not
+    // exhaustively recheck things that have already been checked in a previous
+    // test methods.
+
     /**
      * Returns true if the maps produced by {@link #makeObject()} and {@link 
#makeFullMap()} support the {@code put} and {@code putAll} operations adding new
      * mappings.
@@ -751,11 +760,6 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
         return true;
     }
 
-    // tests begin here. Each test adds a little bit of tested functionality.
-    // Many methods assume previous methods passed. That is, they do not
-    // exhaustively recheck things that have already been checked in a previous
-    // test methods.
-
     /**
      * Returns true if the maps produced by {@link #makeObject()} and {@link 
#makeFullMap()} support the {@code put} and {@code putAll} operations changing
      * existing mappings.
@@ -1312,6 +1316,132 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
         verify();
     }
 
+    /**
+     * Tests {@link Map#computeIfAbsent(Object, java.util.function.Function)}.
+     *
+     * @see Map#putIfAbsent(Object, Object)
+     * @see #testMapPutIfAbsent()
+     */
+    @Test
+    public void testMapComputeIfAbsent() {
+        resetEmpty();
+        final K[] keys = getSampleKeys();
+        final V[] values = getSampleValues();
+        final V[] newValues = getNewSampleValues();
+        if (isPutAddSupported()) {
+            for (final AtomicInteger inc = new AtomicInteger(); inc.get() < 
keys.length; inc.incrementAndGet()) {
+                final int i = inc.get();
+                final K key = keys[i];
+                final V value = values[i];
+                final boolean expectKey = key != null && value != null || key 
== null && !getMap().containsKey(key);
+                final Map<K, V> oldMap = new HashMap<>(getMap());
+                final Object currValue = getMap().computeIfAbsent(key, k -> 
value);
+                // map is updated if new value is not null
+                getConfirmed().computeIfAbsent(key, k -> value);
+                if (!isLazyMapTest()) {
+                    // TODO LazyMap tests do not like this check
+                    verify();
+                }
+                final Supplier<String> messageSupplier = () -> 
String.format("[%,d] map.computeIfAbsent key '%s', value '%s', old %s", 
inc.get(), key, value,
+                        oldMap);
+                assertEquals(value, currValue, messageSupplier);
+                if (isLazyMapTest()) {
+                    // TODO Is there a better way to write generic tests?
+                    assertTrue(getMap().containsKey(key), messageSupplier);
+                    assertTrue(getMap().containsValue(value), messageSupplier);
+                } else {
+                    assertEquals(expectKey, getMap().containsKey(key), 
messageSupplier);
+                    assertEquals(expectKey, getMap().containsValue(value), 
messageSupplier);
+                }
+            }
+            if (isPutChangeSupported()) {
+                // Piggyback on isPutChangeSupported() for computeIfAbsent 
with a caveat for null values.
+                for (int i = 0; i < keys.length; i++) {
+                    final K key = keys[i];
+                    final V newValue = newValues[i];
+                    final boolean newValueAlready = 
getMap().containsValue(newValue);
+                    final V prevValue = getMap().get(key);
+                    final Object oldValue = getMap().putIfAbsent(key, 
newValue);
+                    getConfirmed().putIfAbsent(key, newValue);
+                    if (!isLazyMapTest()) {
+                        // TODO LazyMap tests do not like this check
+                        verify();
+                    }
+                    final V arrValue = values[i];
+                    assertEquals(arrValue, oldValue, "Map.computeIfAbsent 
should return previous value when changed");
+                    assertEquals(prevValue, oldValue, "Map.computeIfAbsent 
should return previous value when changed");
+                    if (prevValue == null) {
+                        assertEquals(newValue, getMap().get(key), 
String.format("[%,d] key '%s', prevValue '%s', newValue '%s'", i, key, 
prevValue, newValue));
+                    } else {
+                        assertEquals(oldValue, getMap().get(key), 
String.format("[%,d] key '%s', prevValue '%s', newValue '%s'", i, key, 
prevValue, newValue));
+                    }
+                    assertTrue(getMap().containsKey(key), "Map should still 
contain key after computeIfAbsent when changed");
+                    if (newValueAlready && newValue != null) {
+                        // TODO The test fixture already contain a null value, 
so we condition this assertion
+                        assertFalse(getMap().containsValue(newValue),
+                                String.format("[%,d] Map at '%s' shouldn't 
contain new value '%s' after computeIfAbsent when changed", i, key, newValue));
+                    }
+                    // if duplicates are allowed, we're not guaranteed that 
the value
+                    // no longer exists, so don't try checking that.
+                    if (!isAllowDuplicateValues() && newValueAlready && 
newValue != null) {
+                        assertFalse(getMap().containsValue(arrValue),
+                                String.format(
+                                        "Map should not contain old value 
after computeIfAbsent when changed: [%,d] key '%s', prevValue '%s', newValue 
'%s'", i,
+                                        key, prevValue, newValue));
+                    }
+                }
+            } else {
+                try {
+                    // two possible exception here, either valid
+                    getMap().putIfAbsent(keys[0], newValues[0]);
+                    fail("Expected IllegalArgumentException or 
UnsupportedOperationException on putIfAbsent (change)");
+                } catch (final IllegalArgumentException | 
UnsupportedOperationException ex) {
+                    // ignore
+                }
+            }
+        } else if (isPutChangeSupported()) {
+            resetEmpty();
+            try {
+                getMap().putIfAbsent(keys[0], values[0]);
+                fail("Expected UnsupportedOperationException or 
IllegalArgumentException on putIfAbsent (add) when fixed size");
+            } catch (final IllegalArgumentException | 
UnsupportedOperationException ex) {
+                // ignore
+            }
+            resetFull();
+            int i = 0;
+            for (final Iterator<K> it = getMap().keySet().iterator(); 
it.hasNext() && i < newValues.length; i++) {
+                final K key = it.next();
+                final V newValue = newValues[i];
+                final boolean newValueAlready = 
getMap().containsValue(newValue);
+                final V prevValue = getMap().get(key);
+                final V oldValue = getMap().putIfAbsent(key, newValue);
+                final V value = getConfirmed().putIfAbsent(key, newValue);
+                verify();
+                assertEquals(value, oldValue, "Map.putIfAbsent should return 
previous value when changed");
+                assertEquals(prevValue, oldValue, "Map.putIfAbsent should 
return previous value when changed");
+                if (prevValue == null) {
+                    assertEquals(newValue, getMap().get(key), 
String.format("[%,d] key '%s', prevValue '%s', newValue '%s'", i, key, 
prevValue, newValue));
+                } else {
+                    assertEquals(oldValue, getMap().get(key), 
String.format("[%,d] key '%s', prevValue '%s', newValue '%s'", i, key, 
prevValue, newValue));
+                }
+                assertTrue(getMap().containsKey(key), "Map should still 
contain key after putIfAbsent when changed");
+                if (newValueAlready && newValue != null) {
+                    // TODO The test fixture already contain a null value, so 
we condition this assertion
+                    assertFalse(getMap().containsValue(newValue),
+                            String.format("[%,d] Map at '%s' shouldn't contain 
new value '%s' after putIfAbsent when changed", i, key, newValue));
+                }
+                // if duplicates are allowed, we're not guaranteed that the 
value
+                // no longer exists, so don't try checking that.
+                if (!isAllowDuplicateValues()) {
+                    assertFalse(getMap().containsValue(values[i]), "Map should 
not contain old value after putIfAbsent when changed");
+                }
+            }
+        } else {
+            assertThrows(UnsupportedOperationException.class, () -> 
getMap().putIfAbsent(keys[0], values[0]),
+                    "Expected UnsupportedOperationException on put (add)");
+        }
+    }
+
     /**
      * Tests Map.containsKey(Object) by verifying it returns false for all 
sample keys on a map created using an empty map and returns true for all sample 
keys
      * returned on a full map.
@@ -1424,8 +1554,10 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
                 assertEquals(otherValue, getMap().getOrDefault(otherKey, 
otherValue));
             }
         }
-        // LazyMap does not like this check:
-        // verify();
+        if (!isLazyMapTest()) {
+            // TODO LazyMap tests do not like this check
+            verify();
+        }
         resetFull();
         for (int i = 0; i < keys.length; i++) {
             assertEquals(values[i], getMap().getOrDefault(keys[i], values[i]));
@@ -1594,6 +1726,8 @@ public abstract class AbstractMapTest<K, V> extends 
AbstractObjectTest {
 
     /**
      * Tests {@link Map#putIfAbsent(Object, Object)}.
+     *
+     * @see Map#computeIfAbsent(Object, java.util.function.Function)
      */
     @Test
     public void testMapPutIfAbsent() {

Reply via email to