diff --git a/eclipse-collections-api/src/main/java/org/eclipse/collections/api/map/ImmutableOrderedMap.java b/eclipse-collections-api/src/main/java/org/eclipse/collections/api/map/ImmutableOrderedMap.java index e6a0499f88..b26916e198 100644 --- a/eclipse-collections-api/src/main/java/org/eclipse/collections/api/map/ImmutableOrderedMap.java +++ b/eclipse-collections-api/src/main/java/org/eclipse/collections/api/map/ImmutableOrderedMap.java @@ -10,6 +10,8 @@ package org.eclipse.collections.api.map; +import java.util.Map; + import org.eclipse.collections.api.block.function.Function; import org.eclipse.collections.api.block.function.Function0; import org.eclipse.collections.api.block.function.Function2; @@ -34,12 +36,35 @@ import org.eclipse.collections.api.list.primitive.ImmutableIntList; import org.eclipse.collections.api.list.primitive.ImmutableLongList; import org.eclipse.collections.api.list.primitive.ImmutableShortList; +import org.eclipse.collections.api.map.primitive.ImmutableObjectDoubleMap; +import org.eclipse.collections.api.map.primitive.ImmutableObjectLongMap; import org.eclipse.collections.api.multimap.list.ImmutableListMultimap; import org.eclipse.collections.api.partition.list.PartitionImmutableList; import org.eclipse.collections.api.tuple.Pair; public interface ImmutableOrderedMap extends OrderedMap, ImmutableMapIterable { + @Override + ImmutableOrderedMap newWithKeyValue(K key, V value); + + @Override + ImmutableOrderedMap newWithAllKeyValues(Iterable> keyValues); + + @Override + ImmutableOrderedMap newWithMap(Map map); + + @Override + ImmutableOrderedMap newWithMapIterable(MapIterable mapIterable); + + @Override + ImmutableOrderedMap newWithAllKeyValueArguments(Pair... keyValuePairs); + + @Override + ImmutableOrderedMap newWithoutKey(K key); + + @Override + ImmutableOrderedMap newWithoutAllKeys(Iterable keys); + @Override ImmutableOrderedMap tap(Procedure procedure); @@ -183,4 +208,18 @@ default ImmutableOrderedMap aggregateBy( ImmutableOrderedMap reduceBy( Function groupBy, Function2 reduceFunction); + + @Override + ImmutableObjectLongMap sumByInt( + Function groupBy, + IntFunction function); + + @Override + ImmutableObjectDoubleMap sumByFloat(Function groupBy, FloatFunction function); + + @Override + ImmutableObjectLongMap sumByLong(Function groupBy, LongFunction function); + + @Override + ImmutableObjectDoubleMap sumByDouble(Function groupBy, DoubleFunction function); } diff --git a/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/immutable/AbstractImmutableMap.java b/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/immutable/AbstractImmutableMap.java index 8d5dbecd71..b0c7d5ea40 100644 --- a/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/immutable/AbstractImmutableMap.java +++ b/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/immutable/AbstractImmutableMap.java @@ -102,7 +102,7 @@ public Map castToMap() @Override public MutableMap toMap() { - return UnifiedMap.newMap(this); + return Maps.mutable.withMap(this); } @Override diff --git a/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/ordered/immutable/ImmutableOrderedMapAdapter.java b/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/ordered/immutable/ImmutableOrderedMapAdapter.java new file mode 100644 index 0000000000..9fb8905fb7 --- /dev/null +++ b/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/ordered/immutable/ImmutableOrderedMapAdapter.java @@ -0,0 +1,678 @@ +/* + * Copyright (c) 2024 Goldman Sachs and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompany this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + */ + +package org.eclipse.collections.impl.map.ordered.immutable; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiConsumer; + +import org.eclipse.collections.api.RichIterable; +import org.eclipse.collections.api.bag.ImmutableBag; +import org.eclipse.collections.api.block.function.Function; +import org.eclipse.collections.api.block.function.Function0; +import org.eclipse.collections.api.block.function.Function2; +import org.eclipse.collections.api.block.function.primitive.BooleanFunction; +import org.eclipse.collections.api.block.function.primitive.ByteFunction; +import org.eclipse.collections.api.block.function.primitive.CharFunction; +import org.eclipse.collections.api.block.function.primitive.DoubleFunction; +import org.eclipse.collections.api.block.function.primitive.FloatFunction; +import org.eclipse.collections.api.block.function.primitive.IntFunction; +import org.eclipse.collections.api.block.function.primitive.LongFunction; +import org.eclipse.collections.api.block.function.primitive.ShortFunction; +import org.eclipse.collections.api.block.predicate.Predicate; +import org.eclipse.collections.api.block.predicate.Predicate2; +import org.eclipse.collections.api.block.procedure.Procedure; +import org.eclipse.collections.api.block.procedure.Procedure2; +import org.eclipse.collections.api.block.procedure.primitive.ObjectIntProcedure; +import org.eclipse.collections.api.list.ImmutableList; +import org.eclipse.collections.api.list.primitive.ImmutableBooleanList; +import org.eclipse.collections.api.list.primitive.ImmutableByteList; +import org.eclipse.collections.api.list.primitive.ImmutableCharList; +import org.eclipse.collections.api.list.primitive.ImmutableDoubleList; +import org.eclipse.collections.api.list.primitive.ImmutableFloatList; +import org.eclipse.collections.api.list.primitive.ImmutableIntList; +import org.eclipse.collections.api.list.primitive.ImmutableLongList; +import org.eclipse.collections.api.list.primitive.ImmutableShortList; +import org.eclipse.collections.api.map.ImmutableOrderedMap; +import org.eclipse.collections.api.map.MapIterable; +import org.eclipse.collections.api.map.MutableOrderedMap; +import org.eclipse.collections.api.map.primitive.ImmutableObjectDoubleMap; +import org.eclipse.collections.api.map.primitive.ImmutableObjectLongMap; +import org.eclipse.collections.api.multimap.list.ImmutableListMultimap; +import org.eclipse.collections.api.ordered.OrderedIterable; +import org.eclipse.collections.api.partition.list.PartitionImmutableList; +import org.eclipse.collections.api.tuple.Pair; +import org.eclipse.collections.impl.map.AbstractMapIterable; +import org.eclipse.collections.impl.map.ordered.mutable.OrderedMapAdapter; + +public class ImmutableOrderedMapAdapter + extends AbstractMapIterable + implements ImmutableOrderedMap, Map, Serializable +{ + private static final long serialVersionUID = 1L; + + private final MutableOrderedMap delegate; + + public ImmutableOrderedMapAdapter(Map delegate) + { + this.delegate = OrderedMapAdapter.adapt(new LinkedHashMap<>(delegate)); + } + + @Override + public int hashCode() + { + return this.delegate.hashCode(); + } + + @Override + public boolean equals(Object obj) + { + return this.delegate.equals(obj); + } + + @Override + public String toString() + { + return this.delegate.toString(); + } + + @Override + public void forEach(BiConsumer action) + { + super.forEach(action); + } + + @Override + public int size() + { + return this.delegate.size(); + } + + @Override + public boolean containsKey(Object key) + { + return this.delegate.containsKey(key); + } + + @Override + public boolean containsValue(Object value) + { + return this.delegate.containsValue(value); + } + + @Override + public V get(Object key) + { + return this.delegate.get(key); + } + + @Override + public void forEachValue(Procedure procedure) + { + this.delegate.forEachValue(procedure); + } + + @Override + public void forEachKey(Procedure procedure) + { + this.delegate.forEachKey(procedure); + } + + @Override + public void forEachKeyValue(Procedure2 procedure) + { + this.delegate.forEachKeyValue(procedure); + } + + @Override + public RichIterable keysView() + { + return this.delegate.keysView(); + } + + @Override + public RichIterable valuesView() + { + return this.delegate.valuesView(); + } + + @Override + public RichIterable> keyValuesView() + { + return this.delegate.keyValuesView(); + } + + @Override + public void forEachWithIndex(ObjectIntProcedure objectIntProcedure) + { + this.delegate.forEachWithIndex(objectIntProcedure); + } + + @Override + public

void forEachWith(Procedure2 procedure, P parameter) + { + this.delegate.forEachWith(procedure, parameter); + } + + @Override + public A ifPresentApply(K key, Function function) + { + return this.delegate.ifPresentApply(key, function); + } + + @Override + public V getIfAbsent(K key, Function0 function) + { + return this.delegate.getIfAbsent(key, function); + } + + @Override + public V getIfAbsentValue(K key, V value) + { + return this.delegate.getIfAbsentValue(key, value); + } + + @Override + public

V getIfAbsentWith( + K key, + Function function, + P parameter) + { + return this.delegate.getIfAbsentWith(key, function, parameter); + } + + @Override + public Map castToMap() + { + return this; + } + + @Override + public Iterator iterator() + { + return this.valuesView().iterator(); + } + + @Override + public void putAll(Map map) + { + throw new UnsupportedOperationException("Cannot call putAll() on " + this.getClass().getSimpleName()); + } + + @Override + public void clear() + { + throw new UnsupportedOperationException("Cannot call clear() on " + this.getClass().getSimpleName()); + } + + @Override + public ImmutableListMultimap flip() + { + return this.delegate.flip().toImmutable(); + } + + @Override + public ImmutableOrderedMap newWithKeyValue(K key, V value) + { + MutableOrderedMap copy = OrderedMapAdapter.adapt(new LinkedHashMap<>(this.delegate)); + copy.put(key, value); + return copy.toImmutable(); + } + + @Override + public ImmutableOrderedMap newWithAllKeyValues(Iterable> keyValues) + { + MutableOrderedMap copy = OrderedMapAdapter.adapt(new LinkedHashMap<>(this.delegate)); + keyValues.forEach(pair -> copy.put(pair.getOne(), pair.getTwo())); + return copy.toImmutable(); + } + + @Override + public ImmutableOrderedMap newWithMap(Map map) + { + MutableOrderedMap copy = OrderedMapAdapter.adapt(new LinkedHashMap<>(this.delegate)); + copy.putAll(map); + return copy.toImmutable(); + } + + @Override + public ImmutableOrderedMap newWithMapIterable(MapIterable mapIterable) + { + MutableOrderedMap copy = OrderedMapAdapter.adapt(new LinkedHashMap<>(this.delegate)); + copy.putAllMapIterable(mapIterable); + return copy.toImmutable(); + } + + @Override + public ImmutableOrderedMap newWithAllKeyValueArguments(Pair... keyValuePairs) + { + MutableOrderedMap copy = OrderedMapAdapter.adapt(new LinkedHashMap<>(this.delegate)); + for (Pair keyValuePair : keyValuePairs) + { + copy.put(keyValuePair.getOne(), keyValuePair.getTwo()); + } + return copy.toImmutable(); + } + + @Override + public ImmutableOrderedMap newWithoutKey(K key) + { + MutableOrderedMap copy = OrderedMapAdapter.adapt(new LinkedHashMap<>(this.delegate)); + copy.removeKey(key); + return copy.toImmutable(); + } + + @Override + public ImmutableOrderedMap newWithoutAllKeys(Iterable keys) + { + MutableOrderedMap copy = OrderedMapAdapter.adapt(new LinkedHashMap<>(this.delegate)); + keys.forEach(copy::removeKey); + return copy.toImmutable(); + } + + @Override + public V put(K key, V value) + { + throw new UnsupportedOperationException("Cannot call put() on " + this.getClass().getSimpleName()); + } + + @Override + public V remove(Object key) + { + throw new UnsupportedOperationException("Cannot call remove() on " + this.getClass().getSimpleName()); + } + + @Override + public ImmutableOrderedMap flipUniqueValues() + { + return this.delegate.flipUniqueValues().toImmutable(); + } + + @Override + public ImmutableOrderedMap collect(Function2> function) + { + return this.delegate.collect(function).toImmutable(); + } + + @Override + public ImmutableOrderedMap collectValues(Function2 function) + { + return this.delegate.collectValues(function).toImmutable(); + } + + @Override + public ImmutableOrderedMap select(Predicate2 predicate) + { + return this.delegate.select(predicate).toImmutable(); + } + + @Override + public ImmutableOrderedMap reject(Predicate2 predicate) + { + return this.delegate.reject(predicate).toImmutable(); + } + + @Override + public V detect(Predicate predicate) + { + return this.delegate.detect(predicate); + } + + @Override + public Optional detectOptional(Predicate predicate) + { + return this.delegate.detectOptional(predicate); + } + + @Override + public ImmutableList collect(Function function) + { + return this.delegate.collect(function).toImmutable(); + } + + @Override + public ImmutableList collectWith(Function2 function, P parameter) + { + return this.delegate.collectWith(function, parameter).toImmutable(); + } + + @Override + public ImmutableBooleanList collectBoolean(BooleanFunction booleanFunction) + { + return this.delegate.collectBoolean(booleanFunction).toImmutable(); + } + + @Override + public ImmutableByteList collectByte(ByteFunction byteFunction) + { + return this.delegate.collectByte(byteFunction).toImmutable(); + } + + @Override + public ImmutableCharList collectChar(CharFunction charFunction) + { + return this.delegate.collectChar(charFunction).toImmutable(); + } + + @Override + public ImmutableDoubleList collectDouble(DoubleFunction doubleFunction) + { + return this.delegate.collectDouble(doubleFunction).toImmutable(); + } + + @Override + public ImmutableFloatList collectFloat(FloatFunction floatFunction) + { + return this.delegate.collectFloat(floatFunction).toImmutable(); + } + + @Override + public ImmutableIntList collectInt(IntFunction intFunction) + { + return this.delegate.collectInt(intFunction).toImmutable(); + } + + @Override + public ImmutableLongList collectLong(LongFunction longFunction) + { + return this.delegate.collectLong(longFunction).toImmutable(); + } + + @Override + public ImmutableShortList collectShort(ShortFunction shortFunction) + { + return this.delegate.collectShort(shortFunction).toImmutable(); + } + + @Override + public ImmutableList collectIf(Predicate predicate, Function function) + { + return this.delegate.collectIf(predicate, function).toImmutable(); + } + + @Override + public ImmutableList flatCollect(Function> function) + { + return this.delegate.flatCollect(function).toImmutable(); + } + + @Override + public ImmutableList select(Predicate predicate) + { + return this.delegate.select(predicate).toImmutable(); + } + + @Override + public

ImmutableList selectWith(Predicate2 predicate, P parameter) + { + return this.delegate.selectWith(predicate, parameter).toImmutable(); + } + + @Override + public ImmutableList reject(Predicate predicate) + { + return this.delegate.reject(predicate).toImmutable(); + } + + @Override + public

ImmutableList rejectWith(Predicate2 predicate, P parameter) + { + return this.delegate.rejectWith(predicate, parameter).toImmutable(); + } + + @Override + public PartitionImmutableList partition(Predicate predicate) + { + return this.delegate.partition(predicate).toImmutable(); + } + + @Override + public

PartitionImmutableList partitionWith(Predicate2 predicate, P parameter) + { + return this.delegate.partitionWith(predicate, parameter).toImmutable(); + } + + @Override + public ImmutableList selectInstancesOf(Class clazz) + { + return this.delegate.selectInstancesOf(clazz).toImmutable(); + } + + @Override + public ImmutableOrderedMap tap(Procedure procedure) + { + this.forEach(procedure); + return this; + } + + @Override + public ImmutableList> zip(Iterable that) + { + return this.delegate.zip(that).toImmutable(); + } + + @Override + public ImmutableList> zipWithIndex() + { + return this.delegate.zipWithIndex().toImmutable(); + } + + @Override + public ImmutableListMultimap groupBy(Function function) + { + return this.delegate.groupBy(function).toImmutable(); + } + + @Override + public ImmutableListMultimap groupByEach(Function> function) + { + return this.delegate.groupByEach(function).toImmutable(); + } + + @Override + public ImmutableOrderedMap groupByUniqueKey(Function function) + { + return this.delegate.groupByUniqueKey(function).toImmutable(); + } + + @Override + public ImmutableOrderedMap aggregateInPlaceBy( + Function groupBy, + Function0 zeroValueFactory, + Procedure2 mutatingAggregator) + { + return this.delegate.aggregateInPlaceBy(groupBy, zeroValueFactory, mutatingAggregator).toImmutable(); + } + + @Override + public ImmutableOrderedMap aggregateBy( + Function groupBy, + Function0 zeroValueFactory, + Function2 nonMutatingAggregator) + { + return this.delegate.aggregateBy(groupBy, zeroValueFactory, nonMutatingAggregator).toImmutable(); + } + + @Override + public ImmutableOrderedMap aggregateBy( + Function keyFunction, + Function valueFunction, + Function0 zeroValueFactory, + Function2 nonMutatingAggregator) + { + return this.delegate.aggregateBy( + keyFunction, + valueFunction, + zeroValueFactory, + nonMutatingAggregator).toImmutable(); + } + + @Override + public ImmutableOrderedMap reduceBy( + Function groupBy, + Function2 reduceFunction) + { + return this.delegate.reduceBy(groupBy, reduceFunction).toImmutable(); + } + + @Override + public ImmutableObjectLongMap sumByInt( + Function groupBy, + IntFunction function) + { + return this.delegate.sumByInt(groupBy, function).toImmutable(); + } + + @Override + public ImmutableObjectDoubleMap sumByFloat( + Function groupBy, + FloatFunction function) + { + return this.delegate.sumByFloat(groupBy, function).toImmutable(); + } + + @Override + public ImmutableObjectLongMap sumByLong( + Function groupBy, + LongFunction function) + { + return this.delegate.sumByLong(groupBy, function).toImmutable(); + } + + @Override + public ImmutableObjectDoubleMap sumByDouble( + Function groupBy, + DoubleFunction function) + { + return this.delegate.sumByDouble(groupBy, function).toImmutable(); + } + + @Override + public ImmutableOrderedMap toReversed() + { + return this.delegate.toReversed().toImmutable(); + } + + @Override + public ImmutableOrderedMap take(int count) + { + return this.delegate.take(count).toImmutable(); + } + + @Override + public ImmutableOrderedMap takeWhile(Predicate predicate) + { + return this.delegate.takeWhile(predicate).toImmutable(); + } + + @Override + public ImmutableOrderedMap drop(int count) + { + return this.delegate.drop(count).toImmutable(); + } + + @Override + public ImmutableOrderedMap dropWhile(Predicate predicate) + { + return this.delegate.dropWhile(predicate).toImmutable(); + } + + @Override + public PartitionImmutableList partitionWhile(Predicate predicate) + { + return this.delegate.partitionWhile(predicate).toImmutable(); + } + + @Override + public ImmutableList distinct() + { + return this.delegate.distinct().toImmutable(); + } + + @Override + public ImmutableOrderedMap toImmutable() + { + return this; + } + + @Override + public Pair detect(Predicate2 predicate) + { + return this.delegate.detect(predicate); + } + + @Override + public Optional> detectOptional(Predicate2 predicate) + { + return this.delegate.detectOptional(predicate); + } + + @Override + public int detectIndex(Predicate predicate) + { + return this.delegate.detectIndex(predicate); + } + + @Override + public int detectLastIndex(Predicate predicate) + { + return this.delegate.detectLastIndex(predicate); + } + + @Override + public boolean corresponds(OrderedIterable other, Predicate2 predicate) + { + return this.delegate.corresponds(other, predicate); + } + + @Override + public void forEach(int startIndex, int endIndex, Procedure procedure) + { + this.delegate.forEach(startIndex, endIndex, procedure); + } + + @Override + public void forEachWithIndex(int fromIndex, int toIndex, ObjectIntProcedure objectIntProcedure) + { + this.delegate.forEachWithIndex(fromIndex, toIndex, objectIntProcedure); + } + + // TODO: Change this to return ImmutableOrderedBag once we support it + @Override + public ImmutableBag countByEach(Function> function) + { + return this.delegate.countByEach(function).toImmutable(); + } + + @Override + public Set keySet() + { + return Collections.unmodifiableSet(this.delegate.keySet()); + } + + @Override + public Collection values() + { + return Collections.unmodifiableCollection(this.delegate.values()); + } + + @Override + public Set> entrySet() + { + return Collections.unmodifiableSet(this.delegate.entrySet()); + } +} diff --git a/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/ordered/mutable/OrderedMapAdapter.java b/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/ordered/mutable/OrderedMapAdapter.java index fc3a157a55..2b582db171 100644 --- a/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/ordered/mutable/OrderedMapAdapter.java +++ b/eclipse-collections/src/main/java/org/eclipse/collections/impl/map/ordered/mutable/OrderedMapAdapter.java @@ -77,6 +77,7 @@ import org.eclipse.collections.impl.collection.mutable.CollectionAdapter; import org.eclipse.collections.impl.list.fixed.ArrayAdapter; import org.eclipse.collections.impl.map.AbstractMapIterable; +import org.eclipse.collections.impl.map.ordered.immutable.ImmutableOrderedMapAdapter; import org.eclipse.collections.impl.multimap.list.FastListMultimap; import org.eclipse.collections.impl.partition.list.PartitionFastList; import org.eclipse.collections.impl.set.mutable.SetAdapter; @@ -381,7 +382,7 @@ public MutableOrderedMap asUnmodifiable() @Override public ImmutableOrderedMap toImmutable() { - throw new UnsupportedOperationException(this.getClass().getSimpleName() + ".toImmutable() not implemented yet"); + return new ImmutableOrderedMapAdapter<>(this); } @Override diff --git a/unit-tests-java8/src/test/java/org/eclipse/collections/test/map/immutable/ordered/ImmutableOrderedMapTest.java b/unit-tests-java8/src/test/java/org/eclipse/collections/test/map/immutable/ordered/ImmutableOrderedMapTest.java new file mode 100644 index 0000000000..c043162436 --- /dev/null +++ b/unit-tests-java8/src/test/java/org/eclipse/collections/test/map/immutable/ordered/ImmutableOrderedMapTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2021 Two Sigma and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompany this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + */ + +package org.eclipse.collections.test.map.immutable.ordered; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.collections.api.map.MutableOrderedMap; +import org.eclipse.collections.impl.map.ordered.immutable.ImmutableOrderedMapAdapter; +import org.eclipse.collections.impl.map.ordered.mutable.OrderedMapAdapter; +import org.eclipse.collections.impl.tuple.ImmutableEntry; +import org.eclipse.collections.test.FixedSizeIterableTestCase; +import org.eclipse.collections.test.map.OrderedMapIterableTestCase; +import org.eclipse.collections.test.map.mutable.MapTestCase; +import org.junit.jupiter.api.Test; + +import static org.eclipse.collections.test.IterableTestCase.assertIterablesEqual; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +public class ImmutableOrderedMapTest + implements OrderedMapIterableTestCase, FixedSizeIterableTestCase, MapTestCase +{ + @Override + public ImmutableOrderedMapAdapter newWith(T... elements) + { + int i = elements.length; + MutableOrderedMap result = OrderedMapAdapter.adapt(new LinkedHashMap<>()); + for (T each : elements) + { + assertNull(result.put(i, each)); + i--; + } + + return (ImmutableOrderedMapAdapter) result.toImmutable(); + } + + @Override + public ImmutableOrderedMapAdapter newWithKeysValues(Object... elements) + { + if (elements.length % 2 != 0) + { + fail(String.valueOf(elements.length)); + } + + MutableOrderedMap result = OrderedMapAdapter.adapt(new LinkedHashMap<>()); + for (int i = 0; i < elements.length; i += 2) + { + assertNull(result.put((K) elements[i], (V) elements[i + 1])); + } + return (ImmutableOrderedMapAdapter) result.toImmutable(); + } + + @Override + public boolean supportsNullKeys() + { + return true; + } + + @Override + public boolean supportsNullValues() + { + return true; + } + + @Override + public void Iterable_toString() + { + OrderedMapIterableTestCase.super.Iterable_toString(); + MapTestCase.super.Iterable_toString(); + } + + @Override + public void Map_remove() + { + Map map = this.newWith(); + assertThrows(UnsupportedOperationException.class, () -> map.remove(2)); + } + + @Override + public void Map_entrySet_remove() + { + Map map = this.newWithKeysValues(); + assertThrows(UnsupportedOperationException.class, () -> map.entrySet().remove(ImmutableEntry.of(null, null))); + } + + @Override + public void Map_clear() + { + Map map = this.newWith("Three", "Two", "One"); + assertThrows(UnsupportedOperationException.class, map::clear); + } + + @Override + @Test + public void Map_put() + { + Map map = this.newWithKeysValues(3, "Three", 2, "Two", 1, "One"); + assertThrows(UnsupportedOperationException.class, () -> map.put(4, "Four")); + assertThrows(UnsupportedOperationException.class, () -> map.put(1, "One")); + assertThrows(UnsupportedOperationException.class, () -> map.put(5, null)); + assertThrows(UnsupportedOperationException.class, () -> map.put(null, "Six")); + assertIterablesEqual(this.newWithKeysValues(3, "Three", 2, "Two", 1, "One"), map); + } + + @Test + @Override + public void Map_putAll() + { + Map map = this.newWithKeysValues(3, "Three", 2, "2"); + Map toAdd = this.newWithKeysValues(2, "Two", 1, "One"); + + assertThrows(UnsupportedOperationException.class, () -> map.putAll(toAdd)); + + Map expected = this.newWithKeysValues(3, "Three", 2, "2"); + assertIterablesEqual(expected, map); + + assertThrows(UnsupportedOperationException.class, () -> map.putAll(null)); + assertThrows(UnsupportedOperationException.class, () -> map.putAll(Map.of())); + } + + @Override + public void Map_merge() + { + Map map = this.newWithKeysValues(1, "1", 2, "2", 3, "3"); + assertThrows(UnsupportedOperationException.class, () -> map.merge(3, "4", (v1, v2) -> { + fail("Expected lambda not to be called on unmodifiable map"); + return null; + })); + assertThrows(UnsupportedOperationException.class, () -> map.merge(4, "4", (v1, v2) -> { + fail("Expected lambda not to be called on unmodifiable map"); + return null; + })); + assertEquals(this.newWithKeysValues(1, "1", 2, "2", 3, "3"), map); + } +}