You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tn...@apache.org on 2014/04/06 21:58:38 UTC
svn commit: r1585335 - in /commons/proper/collections/trunk/src:
main/java/org/apache/commons/collections4/
main/java/org/apache/commons/collections4/multimap/
test/java/org/apache/commons/collections4/collection/
test/java/org/apache/commons/collectio...
Author: tn
Date: Sun Apr 6 19:58:37 2014
New Revision: 1585335
URL: http://svn.apache.org/r1585335
Log:
[COLLECTIONS-508] Improved original contribution after feedback. Thanks to Dipanjan Laha.
Added:
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java (with props)
Modified:
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/AbstractCollectionTest.java
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/MultiValuedMap.java Sun Apr 6 19:58:37 2014
@@ -284,4 +284,24 @@ public interface MultiValuedMap<K, V> {
*/
Collection<V> values();
+ /**
+ * Returns a {@link Map} view of this MultiValuedMap with a Collection as
+ * its value. The Collection holds all the values mapped to that key.
+ *
+ * @return a Map view of the mappings in this MultiValuedMap
+ */
+ Map<K, Collection<V>> asMap();
+
+ // Iterators
+
+ /**
+ * Obtains a <code>MapIterator</code> over the map.
+ * <p>
+ * A map iterator is an efficient way of iterating over maps. There is no
+ * need to access the entries collection or use Map Entry objects.
+ *
+ * @return a map iterator
+ */
+ MapIterator<K, V> mapIterator();
+
}
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java?rev=1585335&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java Sun Apr 6 19:58:37 2014
@@ -0,0 +1,71 @@
+/*
+ * 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.commons.collections4;
+
+import java.util.Set;
+
+/**
+ * Defines a map that holds a set of values against each key.
+ * <p>
+ * A <code>SetValuedMap</code> is a Map with slightly different semantics:
+ * <ul>
+ * <li>Putting a value into the map will add the value to a <code>Set</code> at
+ * that key.</li>
+ * <li>Getting a value will return a <code>Set</code>, holding all the values
+ * put to that key.</li>
+ * </ul>
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public interface SetValuedMap<K, V> extends MultiValuedMap<K, V> {
+
+ /**
+ * Gets the set of values associated with the specified key.
+ * <p>
+ * Implementations typically return <code>null</code> if no values have been
+ * mapped to the key, however the implementation may choose to return an
+ * empty collection.
+ * <p>
+ * Implementations may choose to return a clone of the internal collection.
+ *
+ * @param key the key to retrieve
+ * @return the <code>Set</code> of values, implementations should return
+ * <code>null</code> for no mapping, but may return an empty
+ * collection
+ * @throws ClassCastException if the key is of an invalid type
+ * @throws NullPointerException if the key is null and null keys are invalid
+ */
+ Set<V> get(Object key);
+
+ /**
+ * Removes all values associated with the specified key.
+ * <p>
+ * Implementations typically return <code>null</code> from a subsequent
+ * <code>get(Object)</code>, however they may choose to return an empty
+ * collection.
+ *
+ * @param key the key to remove values from
+ * @return the <code>Set</code> of values removed, implementations should
+ * return <code>null</code> for no mapping found, but may return an
+ * empty collection
+ * @throws UnsupportedOperationException if the map is unmodifiable
+ * @throws ClassCastException if the key is of an invalid type
+ * @throws NullPointerException if the key is null and null keys are invalid
+ */
+ Set<V> remove(Object key);
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/SetValuedMap.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java Sun Apr 6 19:58:37 2014
@@ -27,15 +27,20 @@ import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Factory;
+import org.apache.commons.collections4.IteratorUtils;
+import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.bag.HashBag;
import org.apache.commons.collections4.functors.InstantiateFactory;
-import org.apache.commons.collections4.iterators.EmptyIterator;
+import org.apache.commons.collections4.iterators.EmptyMapIterator;
import org.apache.commons.collections4.iterators.IteratorChain;
import org.apache.commons.collections4.iterators.LazyIteratorChain;
import org.apache.commons.collections4.iterators.TransformIterator;
+import org.apache.commons.collections4.keyvalue.AbstractMapEntry;
+import org.apache.commons.collections4.set.UnmodifiableSet;
/**
* Abstract implementation of the {@link MultiValuedMap} interface to simplify
@@ -85,6 +90,30 @@ public class AbstractMultiValuedMap<K, V
}
/**
+ * Constructor that wraps (not copies).
+ *
+ * @param <C> the collection type
+ * @param map the map to wrap, must not be null
+ * @param initialCollectionCapacity the initial capacity of the collection
+ * @param collectionClazz the collection class
+ * @throws IllegalArgumentException if the map is null or if
+ * initialCollectionCapacity is negetive
+ */
+ @SuppressWarnings("unchecked")
+ protected <C extends Collection<V>> AbstractMultiValuedMap(final Map<K, ? super C> map,
+ int initialCollectionCapacity, final Class<C> collectionClazz) {
+ if (map == null) {
+ throw new IllegalArgumentException("Map must not be null");
+ }
+ if (initialCollectionCapacity < 0) {
+ throw new IllegalArgumentException("Illegal Capacity: " + initialCollectionCapacity);
+ }
+ this.map = (Map<K, Collection<V>>) map;
+ this.collectionFactory = new InstantiateFactory<C>(collectionClazz, new Class[] { Integer.TYPE },
+ new Object[] { new Integer(initialCollectionCapacity) });
+ }
+
+ /**
* Gets the map being wrapped.
*
* @return the wrapped map
@@ -119,7 +148,7 @@ public class AbstractMultiValuedMap<K, V
* {@inheritDoc}
*/
public boolean containsMapping(Object key, Object value) {
- final Collection<V> col = get(key);
+ final Collection<V> col = getMap().get(key);
if (col == null) {
return false;
}
@@ -134,15 +163,16 @@ public class AbstractMultiValuedMap<K, V
}
/**
- * Gets the collection of values associated with the specified key.
+ * Gets the collection of values associated with the specified key. This
+ * would return an empty collection in case the mapping is not present
*
* @param key the key to retrieve
- * @return the <code>Collection</code> of values, will return
- * <code>null</code> for no mapping
+ * @return the <code>Collection</code> of values, will return an empty
+ * <code>Collection</code> for no mapping
* @throws ClassCastException if the key is of an invalid type
*/
public Collection<V> get(Object key) {
- return getMap().get(key);
+ return new WrappedCollection(key);
}
/**
@@ -174,7 +204,7 @@ public class AbstractMultiValuedMap<K, V
*/
public boolean removeMapping(K key, V item) {
boolean result = false;
- final Collection<V> col = get(key);
+ final Collection<V> col = getMap().get(key);
if (col == null) {
return false;
}
@@ -245,7 +275,7 @@ public class AbstractMultiValuedMap<K, V
*/
public V put(K key, V value) {
boolean result = false;
- Collection<V> coll = get(key);
+ Collection<V> coll = getMap().get(key);
if (coll == null) {
coll = createCollection();
coll.add(value);
@@ -313,6 +343,13 @@ public class AbstractMultiValuedMap<K, V
}
/**
+ * {@inheritDoc}
+ */
+ public Map<K, Collection<V>> asMap() {
+ return getMap();
+ }
+
+ /**
* Adds Iterable values to the collection associated with the specified key.
*
* @param key the key to store against
@@ -326,7 +363,7 @@ public class AbstractMultiValuedMap<K, V
}
Iterator<? extends V> it = values.iterator();
boolean result = false;
- Collection<V> coll = get(key);
+ Collection<V> coll = getMap().get(key);
if (coll == null) {
coll = createCollection(); // might produce a non-empty collection
while (it.hasNext()) {
@@ -351,31 +388,13 @@ public class AbstractMultiValuedMap<K, V
}
/**
- * Gets an iterator for the collection mapped to the specified key.
- *
- * @param key the key to get an iterator for
- * @return the iterator of the collection at the key, empty iterator if key
- * not in map
- */
- public Iterator<V> iterator(final Object key) {
- if (!containsKey(key)) {
- return EmptyIterator.<V> emptyIterator();
- }
- return new ValuesIterator(key);
- }
-
- /**
- * Gets the size of the collection mapped to the specified key.
- *
- * @param key the key to get size for
- * @return the size of the collection at the key, zero if key not in map
+ * {@inheritDoc}
*/
- public int size(final Object key) {
- final Collection<V> coll = get(key);
- if (coll == null) {
- return 0;
+ public MapIterator<K, V> mapIterator() {
+ if (size() == 0) {
+ return EmptyMapIterator.<K, V>emptyMapIterator();
}
- return coll.size();
+ return new MultiValuedMapIterator();
}
@SuppressWarnings("rawtypes")
@@ -433,6 +452,190 @@ public class AbstractMultiValuedMap<K, V
// -----------------------------------------------------------------------
/**
+ * Wrapped collection to handle add and remove on the collection returned by get(object)
+ */
+ private class WrappedCollection implements Collection<V> {
+
+ private final Object key;
+
+ public WrappedCollection(Object key) {
+ this.key = key;
+ }
+
+ private Collection<V> getMapping() {
+ return getMap().get(key);
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean add(V value) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ V addedVal = AbstractMultiValuedMap.this.put((K) key, value);
+ return addedVal != null ? true : false;
+ }
+ return col.add(value);
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean addAll(Collection<? extends V> c) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return AbstractMultiValuedMap.this.putAll((K) key, c);
+ }
+ return col.addAll(c);
+ }
+
+ public void clear() {
+ final Collection<V> col = getMapping();
+ if (col != null) {
+ col.clear();
+ AbstractMultiValuedMap.this.remove(key);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public Iterator<V> iterator() {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return (Iterator<V>) IteratorUtils.EMPTY_ITERATOR;
+ }
+ return new ValuesIterator(key);
+ }
+
+ public int size() {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return 0;
+ }
+ return col.size();
+ }
+
+ public boolean contains(Object o) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return false;
+ }
+ return col.contains(o);
+ }
+
+ public boolean containsAll(Collection<?> o) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return false;
+ }
+ return col.containsAll(o);
+ }
+
+ public boolean isEmpty() {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return true;
+ }
+ return col.isEmpty();
+ }
+
+ public boolean remove(Object item) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return false;
+ }
+
+ boolean result = col.remove(item);
+ if (col.isEmpty()) {
+ AbstractMultiValuedMap.this.remove(key);
+ }
+ return result;
+ }
+
+ public boolean removeAll(Collection<?> c) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return false;
+ }
+
+ boolean result = col.removeAll(c);
+ if (col.isEmpty()) {
+ AbstractMultiValuedMap.this.remove(key);
+ }
+ return result;
+ }
+
+ public boolean retainAll(Collection<?> c) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return false;
+ }
+
+ boolean result = col.retainAll(c);
+ if (col.isEmpty()) {
+ AbstractMultiValuedMap.this.remove(key);
+ }
+ return result;
+ }
+
+ public Object[] toArray() {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return CollectionUtils.EMPTY_COLLECTION.toArray();
+ }
+ return col.toArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return (T[]) CollectionUtils.EMPTY_COLLECTION.toArray(a);
+ }
+ return col.toArray(a);
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean equals(Object other) {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return CollectionUtils.EMPTY_COLLECTION.equals(other);
+ }
+ if (other == null) {
+ return false;
+ }
+ if(!(other instanceof Collection)){
+ return false;
+ }
+ Collection otherCol = (Collection) other;
+ if (col.size() != otherCol.size()) {
+ return false;
+ }
+ for (Object value : col) {
+ if (!otherCol.contains(value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return CollectionUtils.EMPTY_COLLECTION.hashCode();
+ }
+ return col.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ final Collection<V> col = getMapping();
+ if (col == null) {
+ return CollectionUtils.EMPTY_COLLECTION.toString();
+ }
+ return col.toString();
+ }
+
+ }
+
+ /**
* Inner class that provides a Bag<K> keys view
*/
private class KeysBag implements Bag<K> {
@@ -519,7 +722,7 @@ public class AbstractMultiValuedMap<K, V
}
public Set<K> uniqueSet() {
- return keySet();
+ return UnmodifiableSet.<K>unmodifiableSet(keySet());
}
public int size() {
@@ -609,21 +812,9 @@ public class AbstractMultiValuedMap<K, V
final Transformer<V, Entry<K, V>> entryTransformer = new Transformer<V, Entry<K, V>>() {
public Entry<K, V> transform(final V input) {
- return new Entry<K, V>() {
-
- public K getKey() {
- return key;
- }
-
- public V getValue() {
- return input;
- }
-
- public V setValue(V value) {
- throw new UnsupportedOperationException();
- }
- };
+ return new MultiValuedMapEntry(key, input);
}
+
};
return new TransformIterator<V, Entry<K, V>>(new ValuesIterator(key), entryTransformer);
}
@@ -638,6 +829,71 @@ public class AbstractMultiValuedMap<K, V
}
/**
+ * Inner class for MultiValuedMap Entries
+ */
+ private class MultiValuedMapEntry extends AbstractMapEntry<K, V> {
+
+ public MultiValuedMapEntry(K key, V value) {
+ super(key, value);
+ }
+
+ @Override
+ public V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ /**
+ * Inner class for MapIterator
+ */
+ private class MultiValuedMapIterator implements MapIterator<K, V> {
+
+ private final Iterator<Entry<K, V>> it;
+
+ private Entry<K, V> current = null;
+
+ public MultiValuedMapIterator() {
+ this.it = AbstractMultiValuedMap.this.entries().iterator();
+ }
+
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ public K next() {
+ current = it.next();
+ return current.getKey();
+ }
+
+ public K getKey() {
+ if (current == null) {
+ throw new IllegalStateException();
+ }
+ return current.getKey();
+ }
+
+ public V getValue() {
+ if (current == null) {
+ throw new IllegalStateException();
+ }
+ return current.getValue();
+ }
+
+ public void remove() {
+ it.remove();
+ }
+
+ public V setValue(V value) {
+ if (current == null) {
+ throw new IllegalStateException();
+ }
+ return current.setValue(value);
+ }
+
+ }
+
+ /**
* Inner class that provides the values view.
*/
private class Values extends AbstractCollection<V> {
@@ -671,7 +927,7 @@ public class AbstractMultiValuedMap<K, V
public ValuesIterator(final Object key) {
this.key = key;
- this.values = get(key);
+ this.values = getMap().get(key);
this.iterator = values.iterator();
}
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java Sun Apr 6 19:58:37 2014
@@ -23,14 +23,14 @@ import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.MultiValuedMap;
/**
* Decorates another <code>MultiValuedMap</code> to provide additional behaviour.
* <p>
- * Each method call made on this <code>MultiValuedMap</code> is forwarded to the
- * decorated <code>MultiValuedMap</code>. This class is used as a framework to
- * build to extensions such as synchronized and unmodifiable behaviour.
+ * Each method call made on this <code>MultiValuedMap</code> is forwarded to the decorated <code>MultiValuedMap</code>.
+ * This class is used as a framework to build to extensions such as synchronized and unmodifiable behaviour.
*
* @param <K> the type of key elements
* @param <V> the type of value elements
@@ -55,7 +55,8 @@ public class AbstractMultiValuedMapDecor
*/
protected AbstractMultiValuedMapDecorator(final MultiValuedMap<K, V> map) {
if (map == null) {
- throw new IllegalArgumentException("MultiValuedMap must not be null");
+ throw new IllegalArgumentException(
+ "MultiValuedMap must not be null");
}
this.map = map;
}
@@ -120,6 +121,10 @@ public class AbstractMultiValuedMapDecor
return decorated().values();
}
+ public Map<K, Collection<V>> asMap() {
+ return decorated().asMap();
+ }
+
public boolean putAll(K key, Iterable<? extends V> values) {
return decorated().putAll(key, values);
}
@@ -132,6 +137,10 @@ public class AbstractMultiValuedMapDecor
decorated().putAll(m);
}
+ public MapIterator<K, V> mapIterator() {
+ return decorated().mapIterator();
+ }
+
@Override
public boolean equals(final Object object) {
if (object == this) {
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java Sun Apr 6 19:58:37 2014
@@ -51,6 +51,16 @@ public class MultiValuedHashMap<K, V> ex
private static final long serialVersionUID = -5845183518195365857L;
/**
+ * The initial capacity used when none specified in constructor.
+ */
+ static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+ /**
+ * The load factor used when none specified in constructor.
+ */
+ static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+ /**
* Creates a MultiValuedHashMap which maps keys to collections of type
* <code>collectionClass</code>.
*
@@ -62,16 +72,57 @@ public class MultiValuedHashMap<K, V> ex
*/
public static <K, V, C extends Collection<V>> MultiValuedMap<K, V> multiValuedMap(
final Class<C> collectionClass) {
- return new MultiValuedHashMap<K, V>(collectionClass);
+ return new MultiValuedHashMap<K, V>(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, collectionClass);
}
/**
- * Creates a MultiValueMap based on a <code>HashMap</code> which stores the
- * multiple values in an <code>ArrayList</code>.
+ * Creates a MultiValueMap based on a <code>HashMap</code> with the default
+ * initial capacity (16) and the default load factor (0.75), which stores
+ * the multiple values in an <code>ArrayList</code>.
*/
@SuppressWarnings("unchecked")
public MultiValuedHashMap() {
- this(ArrayList.class);
+ this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, ArrayList.class);
+ }
+
+ /**
+ * Creates a MultiValueMap based on a <code>HashMap</code> with the initial
+ * capacity and the default load factor (0.75), which stores the multiple
+ * values in an <code>ArrayList</code>.
+ *
+ * @param initialCapacity the initial capacity of the underlying hash map
+ */
+ @SuppressWarnings("unchecked")
+ public MultiValuedHashMap(int initialCapacity) {
+ this(initialCapacity, DEFAULT_LOAD_FACTOR, ArrayList.class);
+ }
+
+ /**
+ * Creates a MultiValueMap based on a <code>HashMap</code> with the initial
+ * capacity and the load factor, which stores the multiple values in an
+ * <code>ArrayList</code>.
+ *
+ * @param initialCapacity the initial capacity of the underlying hash map
+ * @param loadFactor the load factor of the underlying hash map
+ */
+ @SuppressWarnings("unchecked")
+ public MultiValuedHashMap(int initialCapacity, float loadFactor) {
+ this(initialCapacity, loadFactor, ArrayList.class);
+ }
+
+ /**
+ * Creates a MultiValueMap based on a <code>HashMap</code> with the initial
+ * capacity and the load factor, which stores the multiple values in an
+ * <code>ArrayList</code> with the initial collection capacity.
+ *
+ * @param initialCapacity the initial capacity of the underlying hash map
+ * @param loadFactor the load factor of the underlying hash map
+ * @param initialCollectionCapacity the initial capacity of the Collection
+ * of values
+ */
+ @SuppressWarnings("unchecked")
+ public MultiValuedHashMap(int initialCapacity, float loadFactor, int initialCollectionCapacity) {
+ this(initialCapacity, loadFactor, initialCollectionCapacity, ArrayList.class);
}
/**
@@ -81,7 +132,7 @@ public class MultiValuedHashMap<K, V> ex
*/
@SuppressWarnings("unchecked")
public MultiValuedHashMap(final MultiValuedMap<? extends K, ? extends V> map) {
- this(ArrayList.class);
+ this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, ArrayList.class);
super.putAll(map);
}
@@ -92,7 +143,7 @@ public class MultiValuedHashMap<K, V> ex
*/
@SuppressWarnings("unchecked")
public MultiValuedHashMap(final Map<? extends K, ? extends V> map) {
- this(ArrayList.class);
+ this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, ArrayList.class);
super.putAll(map);
}
@@ -100,12 +151,35 @@ public class MultiValuedHashMap<K, V> ex
* Creates a MultiValuedHashMap which creates the value collections using
* the supplied <code>collectionClazz</code>.
*
- * @param <C> the collection type
- * @param collectionClazz the class of the <code>Collection</code> to use to
- * create the value collections
+ * @param initialCapacity the initial capacity of the underlying
+ * <code>HashMap</code>
+ * @param loadFactor the load factor of the underlying <code>HashMap</code>
+ * @param <C> the collection type
+ * @param collectionClazz the class of the <code>Collection</code> to use to
+ * create the value collections
+ */
+ protected <C extends Collection<V>> MultiValuedHashMap(int initialCapacity, float loadFactor,
+ final Class<C> collectionClazz) {
+ super(new HashMap<K, Collection<V>>(initialCapacity, loadFactor), collectionClazz);
+ }
+
+ /**
+ * Creates a MultiValuedHashMap which creates the value collections using
+ * the supplied <code>collectionClazz</code> and the initial collection
+ * capacity .
+ *
+ * @param initialCapacity the initial capacity of the underlying
+ * <code>HashMap</code>
+ * @param loadFactor the load factor of the underlying <code>HashMap</code>
+ * @param initialCollectionCapacity the initial capacity of the
+ * <code>Collection</code>
+ * @param <C> the collection type
+ * @param collectionClazz the class of the <code>Collection</code> to use to
+ * create the value collections
*/
- protected <C extends Collection<V>> MultiValuedHashMap(final Class<C> collectionClazz) {
- super(new HashMap<K, Collection<V>>(), collectionClazz);
+ protected <C extends Collection<V>> MultiValuedHashMap(int initialCapacity, float loadFactor,
+ int initialCollectionCapacity, final Class<C> collectionClazz) {
+ super(new HashMap<K, Collection<V>>(initialCapacity, loadFactor), initialCollectionCapacity, collectionClazz);
}
}
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java Sun Apr 6 19:58:37 2014
@@ -22,10 +22,13 @@ import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.Unmodifiable;
import org.apache.commons.collections4.bag.UnmodifiableBag;
import org.apache.commons.collections4.collection.UnmodifiableCollection;
+import org.apache.commons.collections4.iterators.UnmodifiableMapIterator;
+import org.apache.commons.collections4.map.UnmodifiableMap;
import org.apache.commons.collections4.set.UnmodifiableSet;
/**
@@ -92,6 +95,11 @@ public class UnmodifiableMultiValuedMap<
}
@Override
+ public Collection<V> get(Object key) {
+ return UnmodifiableCollection.<V>unmodifiableCollection(decorated().get(key));
+ }
+
+ @Override
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
@@ -117,6 +125,16 @@ public class UnmodifiableMultiValuedMap<
}
@Override
+ public Map<K, Collection<V>> asMap() {
+ return UnmodifiableMap.<K, Collection<V>>unmodifiableMap(decorated().asMap());
+ }
+
+ @Override
+ public MapIterator<K, V> mapIterator() {
+ return UnmodifiableMapIterator.<K, V>unmodifiableMapIterator(decorated().mapIterator());
+ }
+
+ @Override
public boolean putAll(K key, Iterable<? extends V> values) {
throw new UnsupportedOperationException();
}
Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/AbstractCollectionTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/AbstractCollectionTest.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/AbstractCollectionTest.java (original)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/collection/AbstractCollectionTest.java Sun Apr 6 19:58:37 2014
@@ -703,7 +703,7 @@ public abstract class AbstractCollection
// make sure calls to "containsAll" don't change anything
verify();
- final int min = getFullElements().length < 2 ? 0 : 2;
+ final int min = getFullElements().length < 4 ? 0 : 2;
final int max = getFullElements().length == 1 ? 1 :
getFullElements().length <= 5 ? getFullElements().length - 1 : 5;
col = Arrays.asList(getFullElements()).subList(min, max);
@@ -931,7 +931,7 @@ public abstract class AbstractCollection
resetFull();
final int size = getCollection().size();
- final int min = getFullElements().length < 2 ? 0 : 2;
+ final int min = getFullElements().length < 4 ? 0 : 2;
final int max = getFullElements().length == 1 ? 1 :
getFullElements().length <= 5 ? getFullElements().length - 1 : 5;
final Collection<E> all = Arrays.asList(getFullElements()).subList(min, max);
@@ -985,7 +985,7 @@ public abstract class AbstractCollection
if (getFullElements().length > 1) {
resetFull();
size = getCollection().size();
- final int min = getFullElements().length < 2 ? 0 : 2;
+ final int min = getFullElements().length < 4 ? 0 : 2;
final int max = getFullElements().length <= 5 ? getFullElements().length - 1 : 5;
assertTrue("Collection should changed by partial retainAll",
getCollection().retainAll(elements.subList(min, max)));
Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java (original)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java Sun Apr 6 19:58:37 2014
@@ -23,11 +23,20 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import org.apache.commons.collections4.AbstractObjectTest;
import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.BulkTest;
+import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.MultiValuedMap;
+import org.apache.commons.collections4.bag.AbstractBagTest;
+import org.apache.commons.collections4.bag.CollectionBag;
import org.apache.commons.collections4.bag.HashBag;
+import org.apache.commons.collections4.collection.AbstractCollectionTest;
+import org.apache.commons.collections4.map.AbstractMapTest;
+import org.apache.commons.collections4.set.AbstractSetTest;
/**
* Abstract test class for {@link MultiValuedMap} contract and methods.
@@ -40,6 +49,12 @@ import org.apache.commons.collections4.b
*/
public abstract class AbstractMultiValuedMapTest<K, V> extends AbstractObjectTest {
+ /** Map created by reset(). */
+ protected MultiValuedMap<K, V> map;
+
+ /** MultiValuedHashMap created by reset(). */
+ protected MultiValuedMap<K, V> confirmed;
+
public AbstractMultiValuedMapTest(String testName) {
super(testName);
}
@@ -76,25 +91,108 @@ public abstract class AbstractMultiValue
return true;
}
+ /**
+ * Returns true if the maps produced by {@link #makeObject()} and
+ * {@link #makeFullMap()} supports null keys.
+ * <p>
+ * Default implementation returns true. Override if your collection class
+ * does not support null keys.
+ */
+ public boolean isAllowNullKey() {
+ return true;
+ }
+
+ /**
+ * Returns the set of keys in the mappings used to test the map. This method
+ * must return an array with the same length as {@link #getSampleValues()}
+ * and all array elements must be different. The default implementation
+ * constructs a set of String keys, and includes a single null key if
+ * {@link #isAllowNullKey()} returns <code>true</code>.
+ */
+ @SuppressWarnings("unchecked")
+ public K[] getSampleKeys() {
+ final Object[] result = new Object[] {
+ "one", "one", "two", "two",
+ "three", "three"
+ };
+ return (K[]) result;
+ }
+
+ /**
+ * Returns the set of values in the mappings used to test the map. This
+ * method must return an array with the same length as
+ * {@link #getSampleKeys()}. The default implementation constructs a set of
+ * String values
+ */
+ @SuppressWarnings("unchecked")
+ public V[] getSampleValues() {
+ final Object[] result = new Object[] {
+ "uno", "un", "dos", "deux",
+ "tres", "trois"
+ };
+ return (V[]) result;
+ }
+
protected MultiValuedMap<K, V> makeFullMap() {
final MultiValuedMap<K, V> map = makeObject();
addSampleMappings(map);
return map;
}
- @SuppressWarnings("unchecked")
protected void addSampleMappings(MultiValuedMap<? super K, ? super V> map) {
- map.put((K) "one", (V) "uno");
- map.put((K) "one", (V) "un");
- map.put((K) "two", (V) "dos");
- map.put((K) "two", (V) "deux");
- map.put((K) "three", (V) "tres");
- map.put((K) "three", (V) "trois");
+ final K[] keys = getSampleKeys();
+ final V[] values = getSampleValues();
+ for (int i = 0; i < keys.length; i++) {
+ map.put(keys[i], values[i]);
+ }
}
- public void testNoMappingReturnsNull() {
+ /**
+ * Override to return a MultiValuedMap other than MultiValuedHashMap as the
+ * confirmed map.
+ *
+ * @return a MultiValuedMap that is known to be valid
+ */
+ public MultiValuedMap<K, V> makeConfirmedMap() {
+ return new MultiValuedHashMap<K, V>();
+ }
+
+ public MultiValuedMap<K, V> getConfirmed() {
+ return this.confirmed;
+ }
+
+ public void setConfirmed(MultiValuedMap<K, V> map) {
+ this.confirmed = map;
+ }
+
+ public MultiValuedMap<K, V> getMap() {
+ return this.map;
+ }
+
+ /**
+ * Resets the {@link #map} and {@link #confirmed} fields to empty.
+ */
+ public void resetEmpty() {
+ this.map = makeObject();
+ this.confirmed = makeConfirmedMap();
+ }
+
+ /**
+ * Resets the {@link #map} and {@link #confirmed} fields to full.
+ */
+ public void resetFull() {
+ this.map = makeFullMap();
+ this.confirmed = makeConfirmedMap();
+ final K[] k = getSampleKeys();
+ final V[] v = getSampleValues();
+ for (int i = 0; i < k.length; i++) {
+ confirmed.put(k[i], v[i]);
+ }
+ }
+
+ public void testNoMappingReturnsEmptyCol() {
final MultiValuedMap<K, V> map = makeFullMap();
- assertNull(map.get("whatever"));
+ assertTrue(map.get("whatever").isEmpty());
}
public void testMultipleValues() {
@@ -114,6 +212,69 @@ public abstract class AbstractMultiValue
assertTrue(map.get("three").contains("trois"));
}
+ @SuppressWarnings("unchecked")
+ public void testAddMappingThroughGet(){
+ if (!isAddSupported()) {
+ return;
+ }
+ resetEmpty();
+ final MultiValuedMap<K, V> map = getMap();
+ Collection<V> col1 = map.get("one");
+ Collection<V> col2 = map.get("one");
+ assertTrue(col1.isEmpty());
+ assertTrue(col2.isEmpty());
+ assertEquals(0, map.size());
+ col1.add((V) "uno");
+ col2.add((V) "un");
+ assertTrue(map.containsKey("one"));
+ assertTrue(map.containsMapping("one", "uno"));
+ assertTrue(map.containsMapping("one", "un"));
+ assertTrue(map.containsValue("uno"));
+ assertTrue(map.containsValue("un"));
+ assertTrue(col1.contains("un"));
+ assertTrue(col2.contains("uno"));
+ }
+
+ public void testRemoveMappingThroughGet() {
+ if (!isRemoveSupported()) {
+ return;
+ }
+ resetFull();
+ final MultiValuedMap<K, V> map = getMap();
+ Collection<V> col = map.get("one");
+ assertEquals(2, col.size());
+ assertEquals(6, map.size());
+ col.remove("uno");
+ col.remove("un");
+ assertFalse(map.containsKey("one"));
+ assertFalse(map.containsMapping("one", "uno"));
+ assertFalse(map.containsMapping("one", "un"));
+ assertFalse(map.containsValue("uno"));
+ assertFalse(map.containsValue("un"));
+ assertEquals(4, map.size());
+ assertNull(map.remove("one"));
+ }
+
+ public void testRemoveMappingThroughGetIterator() {
+ if (!isRemoveSupported()) {
+ return;
+ }
+ resetFull();
+ final MultiValuedMap<K, V> map = getMap();
+ Iterator<V> it = map.get("one").iterator();
+ while (it.hasNext()) {
+ it.next();
+ it.remove();
+ }
+ assertFalse(map.containsKey("one"));
+ assertFalse(map.containsMapping("one", "uno"));
+ assertFalse(map.containsMapping("one", "un"));
+ assertFalse(map.containsValue("uno"));
+ assertFalse(map.containsValue("un"));
+ assertEquals(4, map.size());
+ assertNull(map.remove("one"));
+ }
+
public void testContainsValue() {
final MultiValuedMap<K, V> map = makeFullMap();
assertTrue(map.containsValue("uno"));
@@ -158,7 +319,7 @@ public abstract class AbstractMultiValue
// assertEquals(expected, actual);
// }
- public void testRemoveAllViaIterator() {
+ public void testRemoveAllViaValuesIterator() {
if (!isRemoveSupported()) {
return;
}
@@ -167,10 +328,34 @@ public abstract class AbstractMultiValue
i.next();
i.remove();
}
- assertNull(map.get("one"));
+ assertTrue(map.get("one").isEmpty());
assertTrue(map.isEmpty());
}
+ public void testRemoveViaValuesRemove() {
+ if (!isRemoveSupported()) {
+ return;
+ }
+ final MultiValuedMap<K, V> map = makeFullMap();
+ Collection<V> values = map.values();
+ values.remove("uno");
+ values.remove("un");
+ assertFalse(map.containsKey("one"));
+ assertEquals(4, map.size());
+ }
+
+ /*public void testRemoveViaGetCollectionRemove() {
+ if (!isRemoveSupported()) {
+ return;
+ }
+ final MultiValuedMap<K, V> map = makeFullMap();
+ Collection<V> values = map.get("one");
+ values.remove("uno");
+ values.remove("un");
+ assertFalse(map.containsKey("one"));
+ assertEquals(4, map.size());
+ }*/
+
// public void testRemoveAllViaKeyedIterator() {
// if (!isRemoveSupported()) {
// return;
@@ -210,7 +395,7 @@ public abstract class AbstractMultiValue
i.next();
i.remove();
}
- assertNull(map.get("one"));
+ assertTrue(map.get("one").isEmpty());
assertEquals(0, map.size());
}
@@ -459,11 +644,93 @@ public abstract class AbstractMultiValue
assertTrue(keyBag.containsAll(col));
}
-// public void testMapEqulas() {
-// MultiValuedMap<K, V> map1 = makeFullMap();
-// MultiValuedMap<K, V> map2 = makeFullMap();
-// assertEquals(true, map1.equals(map2));
-// }
+ public void testAsMapGet() {
+ resetEmpty();
+ Map<K, Collection<V>> mapCol = getMap().asMap();
+ assertNull(mapCol.get("one"));
+ assertEquals(0, mapCol.size());
+
+ resetFull();
+ mapCol = getMap().asMap();
+ Collection<V> col = mapCol.get("one");
+ assertNotNull(col);
+ assertTrue(col.contains("un"));
+ assertTrue(col.contains("uno"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAsMapPut() {
+ if (!isAddSupported()) {
+ return;
+ }
+ resetEmpty();
+ Map<K, Collection<V>> mapCol = getMap().asMap();
+ Collection<V> col = (Collection<V>) Arrays.asList("un", "uno");
+ mapCol.put((K) "one", col);
+ assertEquals(2, getMap().size());
+ assertTrue(getMap().containsKey("one"));
+ assertTrue(getMap().containsValue("un"));
+ assertTrue(getMap().containsValue("uno"));
+
+ resetFull();
+ mapCol = getMap().asMap();
+ col = mapCol.get("one");
+ col.add((V) "one");
+ assertEquals(7, getMap().size());
+ assertTrue(getMap().containsValue("one"));
+ assertTrue(getMap().containsValue("un"));
+ assertTrue(getMap().containsValue("uno"));
+ }
+
+ public void testAsMapRemove() {
+ if (!isRemoveSupported()) {
+ return;
+ }
+ resetFull();
+ Map<K, Collection<V>> mapCol = getMap().asMap();
+ mapCol.remove("one");
+ assertFalse(getMap().containsKey("one"));
+ assertEquals(4, getMap().size());
+ }
+
+ public void testMapIterator() {
+ resetEmpty();
+ MapIterator<K, V> mapIt = getMap().mapIterator();
+ assertFalse(mapIt.hasNext());
+
+ resetFull();
+ mapIt = getMap().mapIterator();
+ while (mapIt.hasNext()) {
+ K key = mapIt.next();
+ V value = mapIt.getValue();
+ assertTrue(getMap().containsMapping(key, value));
+ }
+ }
+
+ public void testMapIteratorRemove() {
+ if (!isRemoveSupported()) {
+ return;
+ }
+ resetFull();
+ MapIterator<K, V> mapIt = getMap().mapIterator();
+ while (mapIt.hasNext()) {
+ mapIt.next();
+ mapIt.remove();
+ }
+ assertTrue(getMap().isEmpty());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testMapIteratorUnsupportedSet() {
+ resetFull();
+ MapIterator<K, V> mapIt = getMap().mapIterator();
+ mapIt.next();
+ try {
+ mapIt.setValue((V) "some value");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+ }
// -----------------------------------------------------------------------
// Manual serialization testing as this class cannot easily
@@ -472,13 +739,15 @@ public abstract class AbstractMultiValue
public void testEmptyMapCompatibility() throws Exception {
final MultiValuedMap<?, ?> map = makeObject();
- final MultiValuedMap<?, ?> map2 = (MultiValuedMap<?, ?>) readExternalFormFromDisk(getCanonicalEmptyCollectionName(map));
+ final MultiValuedMap<?, ?> map2 =
+ (MultiValuedMap<?, ?>) readExternalFormFromDisk(getCanonicalEmptyCollectionName(map));
assertEquals("Map is empty", 0, map2.size());
}
public void testFullMapCompatibility() throws Exception {
final MultiValuedMap<?, ?> map = (MultiValuedMap<?, ?>) makeFullMap();
- final MultiValuedMap<?, ?> map2 = (MultiValuedMap<?, ?>) readExternalFormFromDisk(getCanonicalFullCollectionName(map));
+ final MultiValuedMap<?, ?> map2 =
+ (MultiValuedMap<?, ?>) readExternalFormFromDisk(getCanonicalFullCollectionName(map));
assertEquals("Map is the right size", map.size(), map2.size());
for (final Object key : map.keySet()) {
assertEquals("Map had inequal elements", map.get(key), map2.get(key));
@@ -491,4 +760,371 @@ public abstract class AbstractMultiValue
}
}
+ // Bulk Tests
+ /**
+ * Bulk test {@link MultiValuedMap#entries()}. This method runs through all
+ * of the tests in {@link AbstractCollectionTest}. After modification
+ * operations, {@link #verify()} is invoked to ensure that the map and the
+ * other collection views are still valid.
+ *
+ * @return a {@link AbstractCollectionTest} instance for testing the map's
+ * values collection
+ */
+ public BulkTest bulkTestMultiValuedMapEntries() {
+ return new TestMultiValuedMapEntries();
+ }
+
+ public class TestMultiValuedMapEntries extends AbstractCollectionTest<Entry<K, V>> {
+ public TestMultiValuedMapEntries() {
+ super("");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Entry<K, V>[] getFullElements() {
+ return makeFullMap().entries().toArray(new Entry[0]);
+ }
+
+ @Override
+ public Collection<Entry<K, V>> makeObject() {
+ return AbstractMultiValuedMapTest.this.makeObject().entries();
+ }
+
+ @Override
+ public Collection<Entry<K, V>> makeFullCollection() {
+ return AbstractMultiValuedMapTest.this.makeFullMap().entries();
+ }
+
+ @Override
+ public boolean isNullSupported() {
+ return AbstractMultiValuedMapTest.this.isAllowNullKey();
+ }
+
+ @Override
+ public boolean isAddSupported() {
+ // Add not supported in entries view
+ return false;
+ }
+
+ @Override
+ public boolean isRemoveSupported() {
+ return AbstractMultiValuedMapTest.this.isRemoveSupported();
+ }
+
+ @Override
+ public boolean isTestSerialization() {
+ return false;
+ }
+
+ @Override
+ public void resetFull() {
+ AbstractMultiValuedMapTest.this.resetFull();
+ setCollection(AbstractMultiValuedMapTest.this.getMap().entries());
+ TestMultiValuedMapEntries.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().entries());
+ }
+
+ @Override
+ public void resetEmpty() {
+ AbstractMultiValuedMapTest.this.resetEmpty();
+ setCollection(AbstractMultiValuedMapTest.this.getMap().entries());
+ TestMultiValuedMapEntries.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().entries());
+ }
+
+ @Override
+ public Collection<Entry<K, V>> makeConfirmedCollection() {
+ // never gets called, reset methods are overridden
+ return null;
+ }
+
+ @Override
+ public Collection<Entry<K, V>> makeConfirmedFullCollection() {
+ // never gets called, reset methods are overridden
+ return null;
+ }
+
+ }
+
+ /**
+ * Bulk test {@link MultiValuedMap#keySet()}. This method runs through all
+ * of the tests in {@link AbstractSetTest}. After modification operations,
+ * {@link #verify()} is invoked to ensure that the map and the other
+ * collection views are still valid.
+ *
+ * @return a {@link AbstractSetTest} instance for testing the map's key set
+ */
+ public BulkTest bulkTestMultiValuedMapKeySet() {
+ return new TestMultiValuedMapKeySet();
+ }
+
+ public class TestMultiValuedMapKeySet extends AbstractSetTest<K> {
+ public TestMultiValuedMapKeySet() {
+ super("");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public K[] getFullElements() {
+ return (K[]) AbstractMultiValuedMapTest.this.makeFullMap().keySet().toArray();
+ }
+
+ @Override
+ public Set<K> makeObject() {
+ return AbstractMultiValuedMapTest.this.makeObject().keySet();
+ }
+
+ @Override
+ public Set<K> makeFullCollection() {
+ return AbstractMultiValuedMapTest.this.makeFullMap().keySet();
+ }
+
+ @Override
+ public boolean isNullSupported() {
+ return AbstractMultiValuedMapTest.this.isAllowNullKey();
+ }
+
+ @Override
+ public boolean isAddSupported() {
+ return false;
+ }
+
+ @Override
+ public boolean isRemoveSupported() {
+ return AbstractMultiValuedMapTest.this.isRemoveSupported();
+ }
+
+ @Override
+ public boolean isTestSerialization() {
+ return false;
+ }
+
+ }
+
+ /**
+ * Bulk test {@link MultiValuedMap#values()}. This method runs through all
+ * of the tests in {@link AbstractCollectionTest}. After modification
+ * operations, {@link #verify()} is invoked to ensure that the map and the
+ * other collection views are still valid.
+ *
+ * @return a {@link AbstractCollectionTest} instance for testing the map's
+ * values collection
+ */
+ public BulkTest bulkTestMultiValuedMapValues() {
+ return new TestMultiValuedMapValues();
+ }
+
+ public class TestMultiValuedMapValues extends AbstractCollectionTest<V> {
+ public TestMultiValuedMapValues() {
+ super("");
+ }
+
+ @Override
+ public V[] getFullElements() {
+ return getSampleValues();
+ }
+
+ @Override
+ public Collection<V> makeObject() {
+ return AbstractMultiValuedMapTest.this.makeObject().values();
+ }
+
+ @Override
+ public Collection<V> makeFullCollection() {
+ return AbstractMultiValuedMapTest.this.makeFullMap().values();
+ }
+
+ @Override
+ public boolean isNullSupported() {
+ return AbstractMultiValuedMapTest.this.isAllowNullKey();
+ }
+
+ @Override
+ public boolean isAddSupported() {
+ return false;
+ }
+
+ @Override
+ public boolean isRemoveSupported() {
+ return AbstractMultiValuedMapTest.this.isRemoveSupported();
+ }
+
+ @Override
+ public boolean isTestSerialization() {
+ return false;
+ }
+
+ @Override
+ public void resetFull() {
+ AbstractMultiValuedMapTest.this.resetFull();
+ setCollection(AbstractMultiValuedMapTest.this.getMap().values());
+ TestMultiValuedMapValues.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().values());
+ }
+
+ @Override
+ public void resetEmpty() {
+ AbstractMultiValuedMapTest.this.resetEmpty();
+ setCollection(AbstractMultiValuedMapTest.this.getMap().values());
+ TestMultiValuedMapValues.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().values());
+ }
+
+ @Override
+ public Collection<V> makeConfirmedCollection() {
+ // never gets called, reset methods are overridden
+ return null;
+ }
+
+ @Override
+ public Collection<V> makeConfirmedFullCollection() {
+ // never gets called, reset methods are overridden
+ return null;
+ }
+
+ }
+
+ /**
+ * Bulk test {@link MultiValuedMap#keys()}. This method runs through all of
+ * the tests in {@link AbstractBagTest}. After modification operations,
+ * {@link #verify()} is invoked to ensure that the map and the other
+ * collection views are still valid.
+ *
+ * @return a {@link AbstractBagTest} instance for testing the map's values
+ * collection
+ */
+ public BulkTest bulkTestMultiValuedMapKeys() {
+ return new TestMultiValuedMapKeys();
+ }
+
+ public class TestMultiValuedMapKeys extends AbstractBagTest<K> {
+
+ public TestMultiValuedMapKeys() {
+ super("");
+ }
+
+ @Override
+ public K[] getFullElements() {
+ return getSampleKeys();
+ }
+
+ @Override
+ public Bag<K> makeObject() {
+ return AbstractMultiValuedMapTest.this.makeObject().keys();
+ }
+
+ @Override
+ public Bag<K> makeFullCollection() {
+ return AbstractMultiValuedMapTest.this.makeFullMap().keys();
+ }
+
+ @Override
+ public boolean isNullSupported() {
+ return AbstractMultiValuedMapTest.this.isAllowNullKey();
+ }
+
+ @Override
+ public boolean isAddSupported() {
+ return false;
+ }
+
+ @Override
+ public boolean isRemoveSupported() {
+ return false;
+ }
+
+ @Override
+ public boolean isTestSerialization() {
+ return false;
+ }
+
+ @Override
+ public void resetFull() {
+ AbstractMultiValuedMapTest.this.resetFull();
+ // wrapping with CollectionBag as otherwise the Collection tests
+ // would fail
+ setCollection(CollectionBag.<K>collectionBag(AbstractMultiValuedMapTest.this.getMap().keys()));
+ TestMultiValuedMapKeys.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().keys());
+ }
+
+ @Override
+ public void resetEmpty() {
+ AbstractMultiValuedMapTest.this.resetEmpty();
+ setCollection(CollectionBag.<K>collectionBag(AbstractMultiValuedMapTest.this.getMap().keys()));
+ TestMultiValuedMapKeys.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().keys());
+ }
+
+ }
+
+ public BulkTest bulkTestAsMap() {
+ return new TestMultiValuedMapAsMap();
+ }
+
+ public class TestMultiValuedMapAsMap extends AbstractMapTest<K, Collection<V>> {
+
+ public TestMultiValuedMapAsMap() {
+ super("");
+ }
+
+ @Override
+ public Map<K, Collection<V>> makeObject() {
+ return AbstractMultiValuedMapTest.this.makeObject().asMap();
+ }
+
+ public Map<K, Collection<V>> makeFullMap() {
+ return AbstractMultiValuedMapTest.this.makeFullMap().asMap();
+ }
+
+ @SuppressWarnings("unchecked")
+ public K[] getSampleKeys() {
+ K[] samplekeys = AbstractMultiValuedMapTest.this.getSampleKeys();
+ Object[] finalKeys = new Object[3];
+ for (int i = 0; i < 3; i++) {
+ finalKeys[i] = samplekeys[i * 2];
+ }
+ return (K[]) finalKeys;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection<V>[] getSampleValues() {
+ V[] sampleValues = AbstractMultiValuedMapTest.this.getSampleValues();
+ Collection<V>[] colArr = new Collection[3];
+ for(int i = 0; i < 3; i++) {
+ colArr[i] = Arrays.asList(sampleValues[i*2], sampleValues[i*2 + 1]);
+ }
+ return colArr;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection<V>[] getNewSampleValues() {
+ Object[] sampleValues = { "ein", "ek", "zwei", "duey", "drei", "teen" };
+ Collection<V>[] colArr = new Collection[3];
+ for (int i = 0; i < 3; i++) {
+ colArr[i] = Arrays.asList((V) sampleValues[i * 2], (V) sampleValues[i * 2 + 1]);
+ }
+ return colArr;
+ }
+
+ @Override
+ public boolean isAllowNullKey() {
+ return AbstractMultiValuedMapTest.this.isAllowNullKey();
+ }
+
+ @Override
+ public boolean isPutAddSupported() {
+ return AbstractMultiValuedMapTest.this.isAddSupported();
+ }
+
+ @Override
+ public boolean isPutChangeSupported() {
+ return AbstractMultiValuedMapTest.this.isAddSupported();
+ }
+
+ @Override
+ public boolean isRemoveSupported() {
+ return AbstractMultiValuedMapTest.this.isRemoveSupported();
+ }
+
+ @Override
+ public boolean isTestSerialization() {
+ return false;
+ }
+
+ }
}
Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java (original)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/MultiValuedHashMapTest.java Sun Apr 6 19:58:37 2014
@@ -17,10 +17,11 @@
package org.apache.commons.collections4.multimap;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashSet;
-import java.util.LinkedList;
+import junit.framework.Test;
+
+import org.apache.commons.collections4.BulkTest;
import org.apache.commons.collections4.MultiValuedMap;
/**
@@ -35,13 +36,17 @@ public class MultiValuedHashMapTest<K, V
super(testName);
}
+ public static Test suite() {
+ return BulkTest.makeSuite(MultiValuedHashMapTest.class);
+ }
+
@Override
public MultiValuedMap<K, V> makeObject() {
final MultiValuedMap<K, V> m = new MultiValuedHashMap<K, V>();
return m;
}
- private <C extends Collection<V>> MultiValuedHashMap<K, V> createTestMap(final Class<C> collectionClass) {
+ /*private <C extends Collection<V>> MultiValuedHashMap<K, V> createTestMap(final Class<C> collectionClass) {
final MultiValuedHashMap<K, V> map =
(MultiValuedHashMap<K, V>) MultiValuedHashMap.<K, V, C> multiValuedMap(collectionClass);
addSampleMappings(map);
@@ -52,26 +57,28 @@ public class MultiValuedHashMapTest<K, V
public void testValueCollectionType() {
final MultiValuedHashMap<K, V> map = createTestMap(LinkedList.class);
assertTrue(map.get("one") instanceof LinkedList);
- }
+ }*/
@SuppressWarnings("unchecked")
public void testPutWithList() {
- final MultiValuedHashMap<K, V> test = (MultiValuedHashMap<K, V>) MultiValuedHashMap.multiValuedMap(ArrayList.class);
+ final MultiValuedHashMap<K, V> test =
+ (MultiValuedHashMap<K, V>) MultiValuedHashMap.multiValuedMap(ArrayList.class);
assertEquals("a", test.put((K) "A", (V) "a"));
assertEquals("b", test.put((K) "A", (V) "b"));
assertEquals(1, test.keySet().size());
- assertEquals(2, test.size("A"));
+ assertEquals(2, test.get("A").size());
assertEquals(2, test.size());
}
@SuppressWarnings("unchecked")
public void testPutWithSet() {
- final MultiValuedHashMap<K, V> test = (MultiValuedHashMap<K, V>) MultiValuedHashMap.multiValuedMap(HashSet.class);
+ final MultiValuedHashMap<K, V> test =
+ (MultiValuedHashMap<K, V>) MultiValuedHashMap.multiValuedMap(HashSet.class);
assertEquals("a", test.put((K) "A", (V) "a"));
assertEquals("b", test.put((K) "A", (V) "b"));
assertEquals(null, test.put((K) "A", (V) "a"));
assertEquals(1, test.keySet().size());
- assertEquals(2, test.size("A"));
+ assertEquals(2, test.get("A").size());
assertEquals(2, test.size());
}
Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java (original)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java Sun Apr 6 19:58:37 2014
@@ -16,6 +16,9 @@
*/
package org.apache.commons.collections4.multimap;
+import junit.framework.Test;
+
+import org.apache.commons.collections4.BulkTest;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.TransformerUtils;
@@ -34,6 +37,10 @@ public class TransformedMultiValuedMapTe
super(testName);
}
+ public static Test suite() {
+ return BulkTest.makeSuite(TransformedMultiValuedMapTest.class);
+ }
+
@Override
public MultiValuedMap<K, V> makeObject() {
return TransformedMultiValuedMap.transformingMap(new MultiValuedHashMap<K, V>(),
Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java?rev=1585335&r1=1585334&r2=1585335&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java (original)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java Sun Apr 6 19:58:37 2014
@@ -16,6 +16,18 @@
*/
package org.apache.commons.collections4.multimap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.apache.commons.collections4.Bag;
+import org.apache.commons.collections4.BulkTest;
+import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.Unmodifiable;
@@ -31,6 +43,10 @@ public class UnmodifiableMultiValuedMapT
super(testName);
}
+ public static Test suite() {
+ return BulkTest.makeSuite(UnmodifiableMultiValuedMapTest.class);
+ }
+
public boolean isAddSupported() {
return false;
}
@@ -78,6 +94,167 @@ public class UnmodifiableMultiValuedMapT
}
}
+ @SuppressWarnings("unchecked")
+ public void testUnmodifiableEntries() {
+ resetFull();
+ Collection<Entry<K, V>> entries = getMap().entries();
+ try {
+ entries.clear();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ Iterator<Entry<K, V>> it = entries.iterator();
+ Entry<K, V> entry = it.next();
+ try {
+ it.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ entry.setValue((V) "three");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testUnmodifiableMapIterator() {
+ resetFull();
+ MapIterator<K, V> mapIt = getMap().mapIterator();
+ try {
+ mapIt.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ mapIt.setValue((V) "three");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testUnmodifiableKeySet() {
+ resetFull();
+ Set<K> keySet = getMap().keySet();
+ try {
+ keySet.add((K) "four");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ keySet.remove("four");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ keySet.clear();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ Iterator<K> it = keySet.iterator();
+ try {
+ it.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testUnmodifiableValues() {
+ resetFull();
+ Collection<V> values = getMap().values();
+ try {
+ values.add((V) "four");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ values.remove("four");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ values.clear();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ Iterator<V> it = values.iterator();
+ try {
+ it.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testUnmodifiableAsMap() {
+ resetFull();
+ Map<K, Collection<V>> mapCol = getMap().asMap();
+ try {
+ mapCol.put((K) "four", (Collection<V>) Arrays.asList("four"));
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ mapCol.remove("four");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ mapCol.clear();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ mapCol.clear();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testUnmodifiableKeys() {
+ resetFull();
+ Bag<K> keys = getMap().keys();
+ try {
+ keys.add((K) "four");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ keys.remove("four");
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ try {
+ keys.clear();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+
+ Iterator<K> it = keys.iterator();
+ try {
+ it.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
// public void testCreate() throws Exception {
// writeExternalFormToDisk((java.io.Serializable) makeObject(),
// "src/test/resources/data/test/UnmodifiableMultiValuedMap.emptyCollection.version4.1.obj");