blob: c92bcd401f047d4e8a5f6b911f355c672697250e [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc.
*
* Licensed 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 libcore.java.util;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Spliterator;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.LinkedBlockingDeque;
import junit.framework.AssertionFailedError;
import libcore.junit.junit3.TestCaseWithRules;
import libcore.junit.util.SwitchTargetSdkVersionRule;
import libcore.junit.util.SwitchTargetSdkVersionRule.TargetSdkVersion;
import org.junit.Rule;
import org.junit.rules.TestRule;
import static java.util.Collections.checkedNavigableMap;
import static java.util.Collections.checkedQueue;
import static java.util.Collections.synchronizedNavigableMap;
import static java.util.Collections.unmodifiableNavigableMap;
import static java.util.Spliterator.DISTINCT;
import static java.util.Spliterator.ORDERED;
import static java.util.Spliterator.SIZED;
import static java.util.Spliterator.SUBSIZED;
import static libcore.java.util.SpliteratorTester.assertHasCharacteristics;
public final class CollectionsTest extends TestCaseWithRules {
@Rule
public TestRule switchTargetSdkVersionRule = SwitchTargetSdkVersionRule.getInstance();
private static final Object NOT_A_STRING = new Object();
private static final Object A_STRING = "string";
public void testEmptyEnumeration() {
Enumeration<Object> e = Collections.emptyEnumeration();
assertFalse(e instanceof Serializable);
assertFalse(e.hasMoreElements());
try {
e.nextElement();
fail();
} catch (NoSuchElementException expected) {
}
}
public void testEmptyIterator() {
testEmptyIterator(Collections.emptyIterator());
testEmptyIterator(Collections.emptyList().iterator());
testEmptyIterator(Collections.emptySet().iterator());
testEmptyIterator(Collections.emptyMap().keySet().iterator());
testEmptyIterator(Collections.emptyMap().entrySet().iterator());
testEmptyIterator(Collections.emptyMap().values().iterator());
}
private void testEmptyIterator(Iterator<?> i) {
assertFalse(i instanceof Serializable);
assertFalse(i.hasNext());
try {
i.next();
fail();
} catch (NoSuchElementException expected) {
}
try {
i.remove();
fail();
} catch (IllegalStateException expected) {
}
}
public void testEmptyListIterator() {
testEmptyListIterator(Collections.emptyListIterator());
testEmptyListIterator(Collections.emptyList().listIterator());
testEmptyListIterator(Collections.emptyList().listIterator(0));
}
private void testEmptyListIterator(ListIterator<?> i) {
assertFalse(i instanceof Serializable);
assertFalse(i.hasNext());
assertFalse(i.hasPrevious());
assertEquals(0, i.nextIndex());
try {
i.next();
fail();
} catch (NoSuchElementException expected) {
}
assertEquals(-1, i.previousIndex());
try {
i.previous();
fail();
} catch (NoSuchElementException expected) {
}
try {
i.add(null);
fail();
} catch (UnsupportedOperationException expected) {
}
try {
i.remove();
fail();
} catch (IllegalStateException expected) {
}
}
static final class ArrayListInheritor<T> extends ArrayList<T> {
private int numSortCalls = 0;
public ArrayListInheritor(Collection<T> initialElements) {
super(initialElements);
}
@Override
public void sort(Comparator<? super T> c) {
super.sort(c);
numSortCalls++;
}
public int numSortCalls() {
return numSortCalls;
}
}
/**
* Tests that when targetSdk {@code <= 25}, Collections.sort() does not delegate
* to List.sort().
*/
@TargetSdkVersion(25)
public void testSort_nougatOrEarlier_doesNotDelegateToListSort() {
// Nougat MR1 / MR2
ArrayListInheritor<String> list = new ArrayListInheritor<>(Arrays.asList("a", "c", "b"));
assertEquals(0, list.numSortCalls());
Collections.sort(list);
assertEquals(0, list.numSortCalls());
}
@TargetSdkVersion(26)
public void testSort_postNougat_delegatesToListSort() {
ArrayListInheritor<String> list = new ArrayListInheritor<>(Arrays.asList("a", "c", "b"));
assertEquals(0, list.numSortCalls());
Collections.sort(list);
assertEquals(1, list.numSortCalls());
}
@TargetSdkVersion(26)
public void testSort_modcountUnmodifiedForLinkedList() {
// does not throw ConcurrentModificationException
LinkedList<String> list = new LinkedList<>(Arrays.asList("red", "green", "blue", "violet"));
Iterator<String> it = list.iterator();
it.next();
Collections.sort(list);
it.next(); // does not throw ConcurrentModificationException
}
@TargetSdkVersion(26)
public void testSort_modcountModifiedForArrayListAndSubclasses() {
List<String> testData = Arrays.asList("red", "green", "blue", "violet");
ArrayList<String> list = new ArrayList<>(testData);
Iterator<String> it = list.iterator();
it.next();
Collections.sort(list);
try {
it.next();
fail();
} catch (ConcurrentModificationException expected) {
}
list = new ArrayListInheritor<>(testData);
it = list.iterator();
it.next();
Collections.sort(list);
try {
it.next();
fail();
} catch (ConcurrentModificationException expected) {
}
}
/**
* A value type whose {@code compareTo} method returns one of {@code 0},
* {@code Integer.MIN_VALUE} and {@code Integer.MAX_VALUE}.
*/
static final class IntegerWithExtremeComparator
implements Comparable<IntegerWithExtremeComparator> {
private final int value;
public IntegerWithExtremeComparator(int value) {
this.value = value;
}
@Override
public int compareTo(IntegerWithExtremeComparator another) {
if (another.value == this.value) {
return 0;
} else if (another.value > this.value) {
return Integer.MIN_VALUE;
} else {
return Integer.MAX_VALUE;
}
}
}
// http://b/19749094
public void testBinarySearch_comparatorThatReturnsMinAndMaxValue() {
ArrayList<Integer> list = new ArrayList<Integer>(16);
list.add(4);
list.add(9);
list.add(11);
list.add(14);
list.add(16);
int index = Collections.binarySearch(list, 9, new Comparator<Integer>() {
@Override
public int compare(Integer lhs, Integer rhs) {
final int compare = lhs.compareTo(rhs);
if (compare == 0) {
return 0;
} else if (compare < 0) {
return Integer.MIN_VALUE;
} else {
return Integer.MAX_VALUE;
}
}
});
assertEquals(1, index);
ArrayList<IntegerWithExtremeComparator> list2 =
new ArrayList<IntegerWithExtremeComparator>();
list2.add(new IntegerWithExtremeComparator(4));
list2.add(new IntegerWithExtremeComparator(9));
list2.add(new IntegerWithExtremeComparator(11));
list2.add(new IntegerWithExtremeComparator(14));
list2.add(new IntegerWithExtremeComparator(16));
assertEquals(1, Collections.binarySearch(list2, new IntegerWithExtremeComparator(9)));
}
public void testBinarySearch_emptyCollection() {
assertEquals(-1, Collections.binarySearch(new ArrayList<Integer>(), 9));
assertEquals(-1, Collections.binarySearch(new ArrayList<>(), 9, Integer::compareTo));
}
public void testSingletonSpliterator() {
Spliterator<String> sp = Collections.singletonList("spiff").spliterator();
assertEquals(1, sp.estimateSize());
assertEquals(1, sp.getExactSizeIfKnown());
assertNull(sp.trySplit());
assertEquals(true, sp.tryAdvance(value -> assertEquals("spiff", value)));
assertEquals(false, sp.tryAdvance(value -> fail()));
}
public void test_checkedNavigableMap_replaceAll() {
NavigableMap<String, Integer> map = checkedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)),
String.class, Integer.class);
map.replaceAll((k, v) -> 5 * v);
assertEquals(
createMap("key3", 15, "key1", 5, "key4", 20, "key2", 10),
map);
}
public void test_checkedNavigableMap_putIfAbsent() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_putIfAbsent(map,
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_checkedNavigableMap_remove() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_remove(map,
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_checkedNavigableMap_replace$K$V() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_replace$K$V$V(map,
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_checkedNavigableMap_replace$K$V$V() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_replace$K$V$V(map,
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_checkedNavigableMap_computeIfAbsent() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_computeIfAbsent(map,
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_checkedNavigableMap_computeIfPresent() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_computeIfPresent(map, false /* acceptsNullKey */);
}
public void test_checkedNavigableMap_compute() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_compute(map, false /* acceptsNullKey */);
}
public void test_checkedNavigableMap_merge() {
NavigableMap<Integer, Double> map =
checkedNavigableMap(new TreeMap<>(), Integer.class, Double.class);
MapDefaultMethodTester.test_merge(map, false /* acceptsNullKey */);
}
public void test_checkedNavigableMap_navigableKeySet() {
NavigableMap<String, Integer> map = checkedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)),
String.class, Integer.class);
check_navigableSet(
map.navigableKeySet(),
Arrays.asList("key1", "key2", "key3", "key4") /* expectedElementsInOrder */,
"absent" /* absentElement */);
}
public void test_checkedNavigableMap_values() {
NavigableMap<String, Integer> map = checkedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)),
String.class, Integer.class);
check_orderedCollection(map.values(), Arrays.asList(1, 2, 3, 4) /* expectedElementsInOrder */);
}
public void test_checkedNavigableMap_isChecked() {
NavigableMap<String, Integer> delegate = new TreeMap<>();
delegate.put("present", 1);
delegate.put("another key", 2);
check_navigableMap_isChecked(
checkedNavigableMap(delegate, String.class, Integer.class),
"present", 1, "aaa absent", "zzz absent", 42);
}
public void test_checkedNavigableSet() {
NavigableSet set = Collections.checkedNavigableSet(new TreeSet<>(), String.class);
check_navigableSet(set, Arrays.asList(), "absent element");
set.add("element 1");
set.add("element 2");
List<String> elementsInOrder = Arrays.asList("element 1", "element 2");
check_navigableSet(set, elementsInOrder, "absent element");
assertEquals(set, new HashSet<>(elementsInOrder));
assertEquals(new HashSet<>(elementsInOrder), set);
assertEquals(2, set.size());
assertTrue(set.contains("element 1"));
assertTrue(set.contains("element 2"));
assertFalse(set.contains("absent element"));
}
public void test_checkedNavigableSet_isChecked() {
NavigableSet set = Collections.checkedNavigableSet(new TreeSet<>(), String.class);
assertThrowsCce(() -> { set.add(new Object()); });
assertThrowsCce(() -> { set.addAll(Arrays.asList(new Object())); });
}
public void test_checkedQueue() {
Queue queue = checkedQueue(new LinkedBlockingDeque<>(2), CharSequence.class);
assertQueueEmpty(queue);
// Demonstrate that any implementation of CharSequence works by using two
// different ones (StringBuilder and String) as values.
StringBuilder firstElement = new StringBuilder("first element");
assertTrue(queue.add(firstElement));
assertFalse(queue.isEmpty());
assertTrue(queue.add("second element"));
assertEquals(2, queue.size());
assertFalse(queue.offer("third element")); // queue is at capacity
try {
queue.add("third element");
fail();
} catch (IllegalStateException expected) {
}
assertThrowsCce(() -> { queue.add(new Object()); }); // fails the type check
assertEquals(2, queue.size()); // size is unchanged
// element() and peek() don't remove the first element
assertSame(firstElement, queue.element());
assertSame(firstElement, queue.peek());
assertSame(firstElement, queue.poll());
assertSame("second element", queue.poll());
assertQueueEmpty(queue);
assertThrowsCce(() -> { queue.add(new Object()); }); // fails the type check
}
/**
* Asserts properties that should hold for any empty queue.
*/
private static void assertQueueEmpty(Queue queue) {
assertTrue(queue.isEmpty());
assertEquals(0, queue.size());
assertNull(queue.peek());
try {
queue.element();
fail();
} catch (NoSuchElementException expected) {
}
assertNull(queue.poll());
}
public void test_unmodifiableMap_getOrDefault() {
Map<Integer, Double> delegate = new HashMap<>();
delegate.put(2, 12.0);
delegate.put(3, null);
Map<Integer, Double> m = Collections.unmodifiableMap(delegate);
assertEquals(-1.0, m.getOrDefault(1, -1.0));
assertEquals(12.0, m.getOrDefault(2, -1.0));
assertEquals(null, m.getOrDefault(3, -1.0));
}
public void test_unmodifiableMap_forEach() {
Map<Integer, Double> delegate = new HashMap<>();
Map<Integer, Double> replica = new HashMap<>();
delegate.put(1, 10.0);
delegate.put(2, 20.0);
Collections.unmodifiableMap(delegate).forEach(replica::put);
assertEquals(10.0, replica.get(1));
assertEquals(20.0, replica.get(2));
assertEquals(2, replica.size());
}
public void test_unmodifiableMap_putIfAbsent() {
try {
Collections.unmodifiableMap(new HashMap<>()).putIfAbsent(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).putIfAbsent(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableMap_remove() {
try {
Collections.unmodifiableMap(new HashMap<>()).remove(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).remove(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableMap_replace$K$V$V() {
try {
Collections.unmodifiableMap(new HashMap<>()).replace(1, 5.0, 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).replace(1, 5.0, 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableMap_replace$K$V() {
try {
Collections.unmodifiableMap(new HashMap<>()).replace(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).replace(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableMap_computeIfAbsent() {
try {
Collections.unmodifiableMap(new HashMap<>()).computeIfAbsent(1, k -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).computeIfAbsent(1, k -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableMap_computeIfPresent() {
try {
Collections.unmodifiableMap(new HashMap<>()).computeIfPresent(1, (k, v) -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).computeIfPresent(1, (k, v) -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableMap_compute() {
try {
Collections.unmodifiableMap(new HashMap<>()).compute(1, (k, v) -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).compute(1, (k, v) -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableMap_merge() {
try {
Collections.unmodifiableMap(new HashMap<>()).merge(1, 2.0, (k, v) -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
// For existing key
Map<Integer, Double> m = new HashMap<>();
m.put(1, 5.0);
try {
Collections.unmodifiableMap(m).merge(1, 2.0, (k, v) -> 1.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableNavigableMap_empty() {
NavigableMap<String, Integer> map = unmodifiableNavigableMap(new TreeMap<>());
check_unmodifiableNavigableMap_defaultMethods(map,
Arrays.<String>asList(),
Arrays.<Integer>asList(),
"absent key", -1 /* absentValue */);
check_unmodifiableNavigableMap_collectionViews(map,
Arrays.<String>asList(),
Arrays.<Integer>asList(),
"absent key");
}
public void test_unmodifiableNavigableMap_nonEmpty() {
NavigableMap<String, Integer> map = unmodifiableNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
check_unmodifiableNavigableMap_defaultMethods(map,
Arrays.asList("key1", "key2", "key3", "key4"),
Arrays.asList(1, 2, 3, 4),
"absent key", -1 /* absentValue */);
check_unmodifiableNavigableMap_collectionViews(map,
Arrays.asList("key1", "key2", "key3", "key4"),
Arrays.asList(1, 2, 3, 4),
"absent key");
}
public void test_unmodifiableNavigableSet_empty() {
NavigableSet<String> set = Collections.unmodifiableNavigableSet(new TreeSet<>());
check_unmodifiableSet(set, "absent element");
check_navigableSet(set, new ArrayList<>(), "absent element");
}
public void test_unmodifiableNavigableSet_nonEmpty() {
NavigableSet<String> delegate = new TreeSet<>();
NavigableSet<String> set = Collections.unmodifiableNavigableSet(delegate);
delegate.add("pear");
delegate.add("banana");
delegate.add("apple");
delegate.add("melon");
check_unmodifiableNavigableSet(set,
Arrays.asList("apple", "banana", "melon", "pear"),
"absent element");
assertEquals("pear", set.ceiling("nonexistent"));
assertEquals("melon", set.floor("nonexistent"));
}
public void test_synchronizedNavigableMap_replaceAll() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
map.replaceAll((k, v) -> 5 * v);
assertEquals(map, createMap("key3", 15, "key1", 5, "key4", 20, "key2", 10));
}
public void test_synchronizedNavigableMap_putIfAbsent() {
MapDefaultMethodTester.test_putIfAbsent(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_synchronizedNavigableMap_remove() {
MapDefaultMethodTester.test_remove(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_synchronizedNavigableMap_replace$K$V$V() {
MapDefaultMethodTester.test_replace$K$V$V(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_synchronizedNavigableMap_replace$K$V() {
MapDefaultMethodTester.test_replace$K$V(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_synchronizedNavigableMap_computeIfAbsent() {
MapDefaultMethodTester.test_computeIfAbsent(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */, true /* acceptsNullValue */);
}
public void test_synchronizedNavigableMap_computeIfPresent() {
MapDefaultMethodTester.test_computeIfPresent(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */);
}
public void test_synchronizedNavigableMap_compute() {
MapDefaultMethodTester.test_compute(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */);
}
public void test_synchronizedNavigableMap_merge() {
MapDefaultMethodTester.test_merge(
Collections.synchronizedNavigableMap(new TreeMap<>()),
false /* acceptsNullKey */);
}
public void test_synchronizedNavigableMap_keySet() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
// Note: keySet() returns a Collections$UnmodifiableSet (not instanceof NavigableSet)
Set<String> set = map.keySet();
check_orderedSet(set, Arrays.asList("key1", "key2", "key3", "key4"));
}
public void test_synchronizedNavigableMap_navigableKeySet() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
NavigableSet<String> set = map.navigableKeySet();
check_navigableSet(set, Arrays.asList("key1", "key2", "key3", "key4"), "absent element");
}
public void test_synchronizedNavigableMap_descendingMap_descendingKeySet() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
NavigableSet<String> set = map.descendingMap().descendingKeySet();
check_navigableSet(set, Arrays.asList("key1", "key2", "key3", "key4"), "absent element");
}
public void test_synchronizedNavigableMap_descendingKeySet() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
NavigableSet<String> set = map.descendingKeySet();
check_navigableSet(set, Arrays.asList("key4", "key3", "key2", "key1"), "absent element");
}
public void test_synchronizedNavigableMap_descendingMap_keySet() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
// Note: keySet() returns a Collections$UnmodifiableSet (not instanceof NavigableSet)
Set<String> set = map.descendingMap().keySet();
check_orderedSet(set, Arrays.asList("key4", "key3", "key2", "key1"));
}
public void test_synchronizedNavigableMap_descendingMap_navigableKeySet() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
NavigableSet<String> set = map.descendingMap().navigableKeySet();
check_navigableSet(set, Arrays.asList("key4", "key3", "key2", "key1"), "absent element");
}
public void test_synchronizedNavigableMap_values() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
Collection<Integer> values = map.values();
check_orderedCollection(values, Arrays.asList(1, 2, 3, 4));
}
public void test_synchronizedNavigableMap_descendingMap_values() {
NavigableMap<String, Integer> map = synchronizedNavigableMap(
new TreeMap<>(createMap("key3", 3, "key1", 1, "key4", 4, "key2", 2)));
Collection<Integer> values = map.descendingMap().values();
check_orderedCollection(values, Arrays.asList(4, 3, 2, 1));
}
public void test_synchronizedNavigableSet_empty() {
NavigableSet<String> set = Collections.synchronizedNavigableSet(new TreeSet<>());
check_navigableSet(set, new ArrayList<>(), "absent element");
}
public void test_synchronizedNavigableSet_nonEmpty() {
List<String> elements = Arrays.asList("apple", "banana", "melon", "pear");
NavigableSet<String> set = Collections.synchronizedNavigableSet(new TreeSet<>(elements));
check_navigableSet(set, elements, "absent element");
}
private static<K,V> void check_unmodifiableNavigableMap_defaultMethods(NavigableMap<K,V> map,
List<K> keysInOrder, List<V> valuesInOrder, K absentKey, V absentValue) {
check_unmodifiableOrderedMap_defaultMethods(map, keysInOrder, valuesInOrder,
absentKey, absentValue);
List<K> reverseKeys = reverseCopyOf(keysInOrder);
List<V> reverseValues = reverseCopyOf(valuesInOrder);
check_unmodifiableOrderedMap_defaultMethods(map.descendingMap(), reverseKeys,
reverseValues, absentKey, absentValue);
int numEntries = keysInOrder.size();
for (int i = 0; i < numEntries; i++) {
K key = keysInOrder.get(i);
V value = valuesInOrder.get(i);
check_unmodifiableOrderedMap_defaultMethods(
map.headMap(key),
keysInOrder.subList(0, i),
valuesInOrder.subList(0, i),
absentKey,
absentValue);
check_unmodifiableOrderedMap_defaultMethods(
map.headMap(key, false /* inclusive */),
keysInOrder.subList(0, i),
valuesInOrder.subList(0, i),
absentKey,
absentValue);
check_unmodifiableOrderedMap_defaultMethods(
map.headMap(key, true /* inclusive */),
keysInOrder.subList(0, i + 1),
valuesInOrder.subList(0, i + 1),
absentKey,
absentValue);
K lowerKey = map.lowerKey(key);
if (lowerKey != null) {
// headMap inclusive of lowerKey is same as exclusive of key
check_unmodifiableOrderedMap_defaultMethods(
map.headMap(lowerKey, true /* inclusive */),
keysInOrder.subList(0, i),
valuesInOrder.subList(0, i),
absentKey,
absentValue);
}
check_unmodifiableOrderedMap_defaultMethods(
map.tailMap(key),
keysInOrder.subList(i, numEntries),
valuesInOrder.subList(i, numEntries),
absentKey,
absentValue);
check_unmodifiableOrderedMap_defaultMethods(
map.tailMap(key, true /* inclusive */),
keysInOrder.subList(i, numEntries),
valuesInOrder.subList(i, numEntries),
absentKey,
absentValue);
check_unmodifiableOrderedMap_defaultMethods(
map.tailMap(key, false /* inclusive */),
keysInOrder.subList(i + 1, numEntries),
valuesInOrder.subList(i + 1, numEntries),
absentKey,
absentValue);
K higherKey = map.higherKey(key);
if (higherKey != null) {
// headMap inclusive of higherKey is same as exclusive of key
check_unmodifiableOrderedMap_defaultMethods(
map.tailMap(higherKey, true /* inclusive */),
keysInOrder.subList(i + 1, numEntries),
valuesInOrder.subList(i + 1, numEntries),
absentKey,
absentValue);
}
int headSize = map.headMap(absentKey).size();
check_unmodifiableOrderedMap_defaultMethods(
map.headMap(absentKey, true /* inclusive */),
keysInOrder.subList(0, headSize),
valuesInOrder.subList(0, headSize),
absentKey,
absentValue);
check_unmodifiableOrderedMap_defaultMethods(
map.tailMap(absentKey, true /* inclusive */),
keysInOrder.subList(headSize, numEntries),
valuesInOrder.subList(headSize, numEntries),
absentKey,
absentValue);
assertEquals(key, map.floorKey(key));
assertEquals(key, map.ceilingKey(key));
assertEquals(new AbstractMap.SimpleEntry<>(key, value), map.floorEntry(key));
assertEquals(new AbstractMap.SimpleEntry<>(key, value), map.ceilingEntry(key));
}
K floor = map.floorKey(absentKey);
K ceiling = map.ceilingKey(absentKey);
if (numEntries == 0) {
assertNull(floor);
assertNull(ceiling);
} else {
assertFalse(Objects.equals(floor, ceiling));
assertTrue(floor != null || ceiling != null);
assertEquals(ceiling, floor == null ? map.firstKey() : map.higherKey(floor));
assertEquals(floor, ceiling == null ? map.lastKey() : map.lowerKey(ceiling));
}
}
/**
* Tests Map's default methods (getOrDefault, forEach, ...) on the given Map.
*
* @param keysInOrder the expected keys in the map, in iteration order
* @param valuesInOrder the expected values in the map, in iteration order
* @param absentKey a key that does not occur in the map
* @param absentValue a value that does not occur in the map
*/
private static<K,V> void check_unmodifiableOrderedMap_defaultMethods(Map<K,V> map,
List<K> keysInOrder, List<V> valuesInOrder, K absentKey, V absentValue) {
if (keysInOrder.size() != valuesInOrder.size()) {
throw new IllegalArgumentException();
}
Map<K, V> mapCopy = new LinkedHashMap<K, V>(map);
// getOrDefault
int numEntries = keysInOrder.size();
for (int i = 0; i < numEntries; i++) {
assertEquals(valuesInOrder.get(i), map.getOrDefault(keysInOrder.get(i), null));
}
// forEach
List<K> keysCopy = new ArrayList<>();
List<V> valuesCopy = new ArrayList<>();
map.forEach((k, v) -> {
keysCopy.add(k);
valuesCopy.add(v);
});
assertEquals(keysInOrder, keysCopy);
assertEquals(valuesInOrder, valuesCopy);
assertThrowsUoe(() -> { map.putIfAbsent(absentKey, absentValue); });
assertThrowsUoe(() -> { map.remove(absentKey); });
assertThrowsUoe(() -> { map.replace(absentKey, absentValue, absentValue); });
assertThrowsUoe(() -> { map.replace(absentKey, absentValue); });
assertThrowsUoe(() -> { map.computeIfAbsent(absentKey, k -> absentValue); });
assertThrowsUoe(() -> { map.computeIfPresent(absentKey, (k, v) -> absentValue); });
assertThrowsUoe(() -> { map.compute(absentKey, (k, v) -> absentValue); });
assertThrowsUoe(() -> { map.merge(absentKey, absentValue, (k, v) -> absentValue); });
if (numEntries > 0) {
K sampleKey = keysInOrder.get(0);
V sampleValue = valuesInOrder.get(0);
assertThrowsUoe(() -> { map.putIfAbsent(sampleKey, absentValue); });
assertThrowsUoe(() -> { map.remove(sampleKey); });
assertThrowsUoe(() -> { map.replace(sampleKey, sampleValue, absentValue); });
assertThrowsUoe(() -> { map.replace(sampleKey, absentValue); });
assertThrowsUoe(() -> { map.computeIfAbsent(sampleKey, k -> absentValue); });
assertThrowsUoe(() -> { map.computeIfPresent(sampleKey, (k, v) -> absentValue); });
assertThrowsUoe(() -> { map.compute(sampleKey, (k, v) -> absentValue); });
assertThrowsUoe(() -> { map.merge(sampleKey, sampleValue, (k, v) -> absentValue); });
}
// Check that map is unchanged
assertEquals(mapCopy, map);
}
/**
* Tests the various {@code Collection} views of the given Map for contents/
* iteration order consistent with the given expectations.
*/
private static<K,V> void check_unmodifiableNavigableMap_collectionViews(
NavigableMap<K, V> map, List<K> keysInOrder, List<V> valuesInOrder, K absentKey) {
List<K> reverseKeys = reverseCopyOf(keysInOrder);
// keySet
check_unmodifiableSet(map.keySet(), absentKey);
check_orderedSet(map.keySet(), keysInOrder);
// navigableKeySet
check_unmodifiableNavigableSet(map.navigableKeySet(), keysInOrder, absentKey);
// descendingMap -> descendingKeySet
check_unmodifiableNavigableSet(
map.descendingMap().descendingKeySet(), keysInOrder, absentKey);
// descendingKeySet
check_unmodifiableNavigableSet(map.descendingKeySet(), reverseKeys, absentKey);
// descendingMap -> keySet
check_unmodifiableSet(map.descendingMap().keySet(), absentKey);
check_orderedSet(map.descendingMap().keySet(), reverseKeys);
// descendingMap -> navigableKeySet
check_unmodifiableNavigableSet(
map.descendingMap().navigableKeySet(), reverseKeys, absentKey);
// values
check_unmodifiableOrderedCollection(map.values(), valuesInOrder);
check_orderedCollection(map.values(), valuesInOrder);
// descendingValues
check_unmodifiableOrderedCollection(map.descendingMap().values(), reverseCopyOf(valuesInOrder));
check_orderedCollection(map.descendingMap().values(), reverseCopyOf(valuesInOrder));
}
/**
* @param absentKeyHead absent key smaller than {@code presentKey}, under the Map's ordering
* @param absentKeyTail absent key larger than {@code presentKey}, under the Map's ordering
*/
private static<K,V> void check_navigableMap_isChecked(NavigableMap map,
K presentKey, V presentValue, K absentKeyHead, K absentKeyTail, V absentValue) {
check_map_isChecked(map,
presentKey, presentValue, absentKeyHead, absentValue);
check_map_isChecked(map.descendingMap(),
presentKey, presentValue, absentKeyHead, absentValue);
// Need to pass correct absent key since the Map might check for
// range inclusion before checking the type of a value
check_map_isChecked(map.headMap(presentKey, true /* inclusive */),
presentKey, presentValue, absentKeyHead, absentValue);
check_map_isChecked(map.tailMap(presentKey, true /* inclusive */),
presentKey, presentValue, absentKeyTail, absentValue);
}
/**
* Asserts that the given map is checked (rejects keys/values of type Object).
*
* @param map a checked Map that contains the entry (presentKey, preventValue), does not
* contain key absentKey or value absentValue, and rejects keys/types of type Object.
*/
private static<K,V> void check_map_isChecked(Map map,
K presentKey, V presentValue, K absentKey, V absentValue) {
Map copyOfMap = new HashMap(map);
assertEquals(map.get(presentKey), presentValue);
assertFalse(map.containsKey(absentKey));
assertFalse(map.values().contains(absentValue));
assertThrowsCce(() -> { map.replaceAll((k, v) -> new Object()); });
assertThrowsCce(() -> { map.putIfAbsent(presentKey, new Object()); });
assertThrowsCce(() -> { map.putIfAbsent(absentKey, new Object()); });
assertThrowsCce(() -> { map.putIfAbsent(new Object(), presentValue); });
assertThrowsCce(() -> { map.remove(new Object()); });
assertThrowsCce(() -> { map.replace(new Object(), presentValue); });
assertThrowsCce(() -> { map.replace(presentKey, new Object()); });
assertThrowsCce(() -> { map.replace(new Object(), presentValue, absentValue); });
// doesn't throw, but has no effect since oldValue doesn't match
assertFalse(map.replace(presentKey, new Object(), absentValue));
assertThrowsCce(() -> { map.replace(presentKey, presentValue, new Object()); });
assertThrowsCce(() -> { map.computeIfAbsent(new Object(), k -> presentValue); });
// doesn't throw, but has no effect since presentKey is present
assertEquals(presentValue, map.computeIfAbsent(presentKey, k -> new Object()));
assertThrowsCce(() -> { map.computeIfAbsent(absentKey, k -> new Object()); });
assertThrowsCce(() -> { map.computeIfPresent(new Object(), (k, v) -> presentValue); });
assertThrowsCce(() -> { map.computeIfPresent(presentKey, (k, v) -> new Object()); });
// doesn't throw, but has no effect since absentKey is absent
assertNull(map.computeIfPresent(absentKey, (k, v) -> new Object()));
assertThrowsCce(() -> { map.compute(new Object(), (k, v) -> presentValue); });
assertThrowsCce(() -> { map.compute(presentKey, (k, v) -> new Object()); });
assertThrowsCce(() -> { map.compute(absentKey, (k, v) -> new Object()); });
assertThrowsCce(() -> { map.merge(new Object(), presentValue, (v1, v2) -> presentValue); });
assertThrowsCce(() -> { map.merge(presentKey, presentValue, (v1, v2) -> new Object()); });
// doesn't throw, puts (absentKey, absentValue) into the map
map.merge(absentKey, absentValue, (v1, v2) -> new Object());
assertEquals(absentValue, map.remove(absentKey)); // restore previous state
assertThrowsCce(() -> { map.put(new Object(), absentValue); });
assertThrowsCce(() -> { map.put(absentKey, new Object()); });
assertThrowsCce(() -> { map.put(new Object(), presentValue); });
assertThrowsCce(() -> { map.put(presentKey, new Object()); });
assertEquals("map should be unchanged", copyOfMap, map);
}
private static <K> void check_unmodifiableNavigableSet(NavigableSet<K> set,
List<K> expectedElementsInOrder, K absentElement) {
check_unmodifiableSet(set, absentElement);
check_unmodifiableSet(set.descendingSet(), absentElement);
check_navigableSet(set, expectedElementsInOrder, absentElement);
if (!expectedElementsInOrder.isEmpty()) {
K sampleElement = expectedElementsInOrder.get(expectedElementsInOrder.size() / 2);
check_unmodifiableSet(set.headSet(sampleElement), absentElement);
check_unmodifiableSet(set.tailSet(sampleElement), absentElement);
}
}
private static <K> void check_navigableSet(NavigableSet<K> set,
List<K> expectedElementsInOrder, K absentElement) {
check_orderedSet(set, expectedElementsInOrder);
check_set(set, absentElement);
int numElements = set.size();
List<K> reverseOrder = new ArrayList<>(expectedElementsInOrder);
Collections.reverse(reverseOrder);
check_orderedSet(set.descendingSet(), reverseOrder);
for (int i = 0; i < numElements; i++) {
K element = expectedElementsInOrder.get(i);
check_orderedSet(
set.headSet(element),
expectedElementsInOrder.subList(0, i));
check_orderedSet(
set.headSet(element, false /* inclusive */),
expectedElementsInOrder.subList(0, i));
check_orderedSet(
set.headSet(element, true /* inclusive */),
expectedElementsInOrder.subList(0, i + 1));
check_orderedSet(
set.tailSet(element),
expectedElementsInOrder.subList(i, numElements));
check_orderedSet(
set.tailSet(element, true /* inclusive */),
expectedElementsInOrder.subList(i, numElements));
check_orderedSet(
set.tailSet(element, false /* inclusive */),
expectedElementsInOrder.subList(i + 1, numElements));
assertEquals(element, set.floor(element));
assertEquals(element, set.ceiling(element));
}
K floor = set.floor(absentElement);
K ceiling = set.ceiling(absentElement);
if (numElements == 0) {
assertNull(floor);
assertNull(ceiling);
} else {
assertFalse(Objects.equals(floor, ceiling));
assertTrue(floor != null || ceiling != null);
}
}
/**
* Checks a Set that may or may not be instanceof SortedSet / NavigableSet
* for adherence to a specified iteration order.
*/
private static <K> void check_orderedSet(
Set<K> set, List<K> expectedElementsInOrder) {
assertEquals(expectedElementsInOrder, new ArrayList<>(set));
Set<K> copy = new HashSet<>(expectedElementsInOrder);
assertEquals(copy, set);
assertEquals(copy.hashCode(), set.hashCode());
int numElements = set.size();
assertEquals(expectedElementsInOrder.size(), numElements);
Spliterator<K> spliterator = set.spliterator();
SpliteratorTester.runBasicIterationTests(spliterator, expectedElementsInOrder);
if (spliterator.hasCharacteristics(SIZED)) {
SpliteratorTester.runSizedTests(set, numElements);
}
if (spliterator.hasCharacteristics(SUBSIZED)) {
SpliteratorTester.runSubSizedTests(set, numElements);
}
assertHasCharacteristics(ORDERED | DISTINCT, spliterator);
SpliteratorTester.runOrderedTests(set);
}
private static <K> void check_unmodifiableSet(Set<K> set, K absentElement) {
assertThrowsUoe(() -> { set.remove(null); } );
assertThrowsUoe(set::clear);
assertThrowsUoe(() -> { set.add(null); } );
if (set.isEmpty()) {
assertEquals(0, set.size());
} else {
assertTrue(set.size() > 0);
Iterator<K> iterator = set.iterator();
K firstElement = iterator.next();
assertThrowsUoe(() -> { set.remove(firstElement); } );
assertThrowsUoe(iterator::remove);
}
SpliteratorTester.runDistinctTests(set);
check_set(set, absentElement);
}
private static <K> void check_set(Set<K> set, K absentElement) {
// some basic properties that must hold for all sets (regardless of whether
// they're ordered, strict, support null, ...):
if (!set.isEmpty()) {
K sampleElement = set.iterator().next();
assertTrue(set.contains(sampleElement));
}
assertFalse(set.contains(absentElement));
}
private static <V> void check_unmodifiableOrderedCollection(
Collection<V> values, List<V> elementsInOrder) {
assertThrowsUoe(() -> { values.remove(null); } );
assertThrowsUoe(values::clear);
assertThrowsUoe(() -> { values.add(null); } );
Iterator<V> iterator = values.iterator();
if (!elementsInOrder.isEmpty()) {
iterator.next();
assertThrowsUoe(iterator::remove);
assertThrowsUoe(() -> { values.remove(elementsInOrder.get(0)); });
}
check_orderedCollection(values, elementsInOrder);
}
private static <V> void check_orderedCollection(
Collection<V> collection, List<V> elementsInOrder) {
Spliterator<V> spliterator = collection.spliterator();
SpliteratorTester.runBasicIterationTests(spliterator, elementsInOrder);
if (spliterator.hasCharacteristics(SIZED)) {
SpliteratorTester.runSizedTests(collection, elementsInOrder.size());
}
if (spliterator.hasCharacteristics(SUBSIZED)) {
SpliteratorTester.runSubSizedTests(collection, elementsInOrder.size());
}
SpliteratorTester.runOrderedTests(collection);
}
public void test_EmptyMap_getOrDefault() {
Map<Integer, Double> m = Collections.emptyMap();
assertEquals(-1.0, m.getOrDefault(1, -1.0));
assertEquals(-1.0, m.getOrDefault(2, -1.0));
}
public void test_EmptyMap_forEach() {
try {
Collections.emptyMap().forEach(null);
fail();
} catch (NullPointerException expected) {
}
}
public void test_EmptyMap_putIfAbsent() {
try {
Collections.emptyMap().putIfAbsent(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_EmptyMap_remove() {
try {
Collections.emptyMap().remove(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_EmptyMap_replace$K$V$V() {
try {
Collections.emptyMap().replace(1, 5.0, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_EmptyMap_replace$K$V() {
try {
Collections.emptyMap().replace(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_EmptyMap_computeIfAbsent() {
try {
Collections.emptyMap().computeIfAbsent(1, k -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_EmptyMap_computeIfPresent() {
try {
Collections.emptyMap().computeIfPresent(1, (k, v) -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_EmptyMap_compute() {
try {
Collections.emptyMap().compute(1, (k, v) -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_EmptyMap_merge() {
try {
Collections.emptyMap().merge(1, 5.0, (k, v) -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_getOrDefault() {
Map<Integer, Double> m = Collections.singletonMap(1, 11.0);
assertEquals(11.0, m.getOrDefault(1, -1.0));
assertEquals(-1.0, m.getOrDefault(2, -1.0));
}
public void test_SingletonMap_forEach() {
Map<Integer, Double> m = new HashMap<>();
Collections.singletonMap(1, 11.0).forEach(m::put);
assertEquals(11.0, m.getOrDefault(1, -1.0));
assertEquals(1, m.size());
}
public void test_SingletonMap_putIfAbsent() {
try {
Collections.singletonMap(1, 11.0).putIfAbsent(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_remove() {
try {
Collections.singletonMap(1, 11.0).remove(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_replace$K$V$V() {
try {
Collections.singletonMap(1, 11.0).replace(1, 5.0, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_replace$K$V() {
try {
Collections.singletonMap(1, 11.0).replace(1, 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_computeIfAbsent() {
try {
Collections.singletonMap(1, 11.0).computeIfAbsent(1, k -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_computeIfPresent() {
try {
Collections.singletonMap(1, 11.0).computeIfPresent(1, (k, v) -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_compute() {
try {
Collections.singletonMap(1, 11.0).compute(1, (k, v) -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonMap_merge() {
try {
Collections.singletonMap(1, 11.0).merge(1, 5.0, (k, v) -> 5.0);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SynchronizedList_replaceAll() {
ListDefaultMethodTester.test_replaceAll(Collections.synchronizedList(new ArrayList<>()));
}
public void test_SynchronizedList_sort() {
ListDefaultMethodTester.test_sort(Collections.synchronizedList(new ArrayList<>()));
}
public void test_CheckedList_replaceAll() {
ListDefaultMethodTester.test_replaceAll(Collections.checkedList(new ArrayList<>(), Integer.class));
}
public void test_CheckedList_sort() {
ListDefaultMethodTester.test_sort(Collections.checkedList(new ArrayList<>(), Double.class));
}
public void test_EmptyList_replaceAll() {
Collections.emptyList().replaceAll(k -> 1);
try {
Collections.emptyList().replaceAll(null);
fail();
} catch (NullPointerException expected) {
}
}
public void test_EmptyList_sort() {
Collections.emptyList().sort((k1, k2) -> 1);
}
public void test_emptyNavigableMap() {
NavigableMap<String, Integer> map = Collections.emptyNavigableMap();
check_unmodifiableNavigableMap_defaultMethods(
map,
new ArrayList<>() /* keysInOrder */,
new ArrayList<>() /* valuesInOrder */,
"absent key" /* absentKey */,
-1 /* absentValue */
);
check_unmodifiableNavigableMap_collectionViews(
map,
new ArrayList<>() /* keysInOrder */,
new ArrayList<>() /* valuesInOrder */,
"absent key" /* absentKey */);
}
public void test_emptyNavigableSet() {
NavigableSet<String> set = Collections.emptyNavigableSet();
check_unmodifiableNavigableSet(set, new ArrayList<>() /* expectedElementsInOrder */,
"absent element");
check_navigableSet(set, new ArrayList<>() /* expectedElementsInOrder */, "absent element");
}
public void test_emptySortedMap() {
SortedMap<String, Integer> map = Collections.emptySortedMap();
check_unmodifiableOrderedMap_defaultMethods(
map,
new ArrayList<>() /* keysInOrder */,
new ArrayList<>() /* valuesInOrder */,
"absent key" /* absentKey */,
-1 /* absentValue */);
check_unmodifiableSet(map.keySet(), "absent element");
check_orderedSet(map.keySet(), new ArrayList<>() /* expectedElementsInOrder */);
check_unmodifiableSet(map.entrySet(), new AbstractMap.SimpleEntry<>("absent element", 42));
check_orderedCollection(map.values(), new ArrayList<>() /* expectedValuesInOrder */);
}
public void test_emptySortedSet() {
SortedSet<String> set = Collections.emptySortedSet();
check_unmodifiableSet(set, "absent element");
check_orderedSet(set, new ArrayList<>() /* expectedElementsInOrder */);
}
public void test_unmodifiableList_replaceAll() {
try {
Collections.unmodifiableList(new ArrayList<>()).replaceAll(k -> 1);
fail();
} catch (UnsupportedOperationException expected) {
}
// with non empty list
try {
ArrayList l = new ArrayList();
l.add(1);
l.add(2);
Collections.unmodifiableList(l).replaceAll(k -> 1);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_unmodifiableList_sort() {
try {
Collections.unmodifiableList(new ArrayList<>()).sort((k1, k2) -> 1);
fail();
} catch (UnsupportedOperationException expected) {
}
// with non empty list
try {
ArrayList l = new ArrayList();
l.add(1);
l.add(2);
Collections.unmodifiableList(l).sort((k1, k2) -> 1);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonList_replaceAll() {
try {
Collections.singletonList(1).replaceAll(k -> 2);
fail();
} catch (UnsupportedOperationException expected) {
}
}
public void test_SingletonList_sort() {
Collections.singletonList(1).sort((k1, k2) -> 2);
}
public void test_CheckedMap_replaceAll() {
Map<Integer, Integer> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Integer.class);
checkedMap.put(1, 10);
checkedMap.put(2, 20);
checkedMap.put(3, 30);
checkedMap.replaceAll((k, v) -> (Integer)k + (Integer)v);
assertEquals(11, checkedMap.get(1));
assertEquals(22, checkedMap.get(2));
assertEquals(33, checkedMap.get(3));
assertEquals(3, checkedMap.size());
}
public void test_CheckedMap_putIfAbsent() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_putIfAbsent(checkedMap, true /* acceptsNullKey */,
true /* acceptsNullValue */);
// Without generics to check the typeCheck implementation
Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
// When key is present
checkedMap2.putIfAbsent(1, A_STRING);
try {
checkedMap2.putIfAbsent(1, NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
// When key is absent
checkedMap2.clear();
try {
checkedMap2.putIfAbsent(1, NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
}
public void test_CheckedMap_remove() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_remove(checkedMap, true /* acceptsNullKey */,
true /* acceptsNullValue */);
}
public void test_CheckedMap_replace$K$V$V() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_replace$K$V$V(checkedMap, true /* acceptsNullKey */,
true /* acceptsNullValue */);
// Without generics to check the typeCheck implementation
Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
checkedMap2.put(1, A_STRING);
try {
checkedMap2.replace(1, NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
}
public void test_CheckedMap_replace$K$V() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_replace$K$V(checkedMap, true /* acceptsNullKey */,
true /* acceptsNullValue */);
// Without generics to check the typeCheck implementation
Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
checkedMap2.put(1, A_STRING);
try {
checkedMap2.replace(1, 1, NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
}
public void test_CheckedMap_computeIfAbsent() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_computeIfAbsent(checkedMap, true /* acceptsNullKey */,
true /* acceptsNullValue */);
// Without generics to check the typeCheck implementation
Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
checkedMap2.put(1, A_STRING);
// When key is present, function should not be invoked
assertSame(A_STRING, checkedMap2.computeIfAbsent(1, k -> {
throw new AssertionFailedError("key present: function should not be invoked");
}));
// When key is absent, computed value's type should be checked
checkedMap2.clear();
try {
checkedMap2.computeIfAbsent(1, k -> NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
}
public void test_CheckedMap_computeIfPresent() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_computeIfPresent(checkedMap, true /* acceptsNullKey */);
// Without generics to check the typeCheck implementation
Map m = new HashMap();
Map checkedMap2 = Collections.checkedMap(m, Integer.class, String.class);
checkedMap2.put(1, A_STRING);
try {
checkedMap2.computeIfPresent(1, (k, v) -> NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
}
public void test_CheckedMap_compute() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_compute(checkedMap, true /* acceptsNullKey */);
Map checkedMap2 = Collections.checkedMap(new HashMap(), Integer.class, String.class);
checkedMap2.put(1, A_STRING);
try {
checkedMap2.compute(1, (k, v) -> NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
}
public void test_CheckedMap_merge() {
Map<Integer, Double> map = new HashMap<>();
Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
MapDefaultMethodTester.test_merge(checkedMap, true /* acceptsNullKey */);
// Without generics to check the typeCheck implementation
Map checkedMap2 =
Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
checkedMap2.put(1, A_STRING);
try {
checkedMap2.merge(1, A_STRING, (v1, v2) -> NOT_A_STRING);
fail();
} catch (ClassCastException expected) {}
}
private static<K,V> Map<K, V> createMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
Map<K, V> result = new HashMap<>();
result.put(k1, v1);
result.put(k2, v2);
result.put(k3, v3);
result.put(k4, v4);
return result;
}
private static void assertThrowsUoe(Runnable runnable) {
try {
runnable.run();
fail();
} catch (UnsupportedOperationException expected) {
}
}
private static void assertThrowsCce(Runnable runnable) {
try {
runnable.run();
fail();
} catch (ClassCastException expected) {
}
}
private static<T> List<T> reverseCopyOf(List<T> list) {
List<T> result = new LinkedList<>();
for (T element : list) {
result.add(0, element);
}
return result;
}
}