001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing.testers;
018
019import static com.google.common.collect.testing.features.CollectionSize.SEVERAL;
020import static com.google.common.collect.testing.features.CollectionSize.ZERO;
021import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
022import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEY_QUERIES;
023import static com.google.common.collect.testing.features.MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION;
024import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_REMOVE;
025import static org.junit.Assert.assertThrows;
026
027import com.google.common.annotations.GwtCompatible;
028import com.google.common.collect.testing.AbstractMapTester;
029import com.google.common.collect.testing.WrongType;
030import com.google.common.collect.testing.features.CollectionSize;
031import com.google.common.collect.testing.features.MapFeature;
032import java.util.ConcurrentModificationException;
033import java.util.Iterator;
034import java.util.Map.Entry;
035
036/**
037 * A generic JUnit test which tests {@code remove} operations on a map. Can't be invoked directly;
038 * please see {@link com.google.common.collect.testing.MapTestSuiteBuilder}.
039 *
040 * @author George van den Driessche
041 * @author Chris Povirk
042 */
043@GwtCompatible
044public class MapRemoveTester<K, V> extends AbstractMapTester<K, V> {
045  @MapFeature.Require(SUPPORTS_REMOVE)
046  @CollectionSize.Require(absent = ZERO)
047  public void testRemove_present() {
048    int initialSize = getMap().size();
049    assertEquals("remove(present) should return the associated value", v0(), getMap().remove(k0()));
050    assertEquals(
051        "remove(present) should decrease a map's size by one.", initialSize - 1, getMap().size());
052    expectMissing(e0());
053  }
054
055  @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_REMOVE})
056  @CollectionSize.Require(SEVERAL)
057  public void testRemovePresentConcurrentWithEntrySetIteration() {
058    Iterator<Entry<K, V>> iterator = getMap().entrySet().iterator();
059    getMap().remove(k0());
060    assertThrows(ConcurrentModificationException.class, iterator::next);
061  }
062
063  @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_REMOVE})
064  @CollectionSize.Require(SEVERAL)
065  public void testRemovePresentConcurrentWithKeySetIteration() {
066    Iterator<K> iterator = getMap().keySet().iterator();
067    getMap().remove(k0());
068    assertThrows(ConcurrentModificationException.class, iterator::next);
069  }
070
071  @MapFeature.Require({FAILS_FAST_ON_CONCURRENT_MODIFICATION, SUPPORTS_REMOVE})
072  @CollectionSize.Require(SEVERAL)
073  public void testRemovePresentConcurrentWithValuesIteration() {
074    Iterator<V> iterator = getMap().values().iterator();
075    getMap().remove(k0());
076    assertThrows(ConcurrentModificationException.class, iterator::next);
077  }
078
079  @MapFeature.Require(SUPPORTS_REMOVE)
080  public void testRemove_notPresent() {
081    assertNull("remove(notPresent) should return null", getMap().remove(k3()));
082    expectUnchanged();
083  }
084
085  @MapFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_KEYS})
086  @CollectionSize.Require(absent = ZERO)
087  public void testRemove_nullPresent() {
088    initMapWithNullKey();
089
090    int initialSize = getMap().size();
091    assertEquals(
092        "remove(null) should return the associated value",
093        getValueForNullKey(),
094        getMap().remove(null));
095    assertEquals(
096        "remove(present) should decrease a map's size by one.", initialSize - 1, getMap().size());
097    expectMissing(entry(null, getValueForNullKey()));
098  }
099
100  @MapFeature.Require(absent = SUPPORTS_REMOVE)
101  @CollectionSize.Require(absent = ZERO)
102  public void testRemove_unsupported() {
103    assertThrows(UnsupportedOperationException.class, () -> getMap().remove(k0()));
104    expectUnchanged();
105    assertEquals("remove(present) should not remove the element", v0(), get(k0()));
106  }
107
108  @MapFeature.Require(absent = SUPPORTS_REMOVE)
109  public void testRemove_unsupportedNotPresent() {
110    try {
111      assertNull(
112          "remove(notPresent) should return null or throw UnsupportedOperationException",
113          getMap().remove(k3()));
114    } catch (UnsupportedOperationException tolerated) {
115    }
116    expectUnchanged();
117    expectMissing(e3());
118  }
119
120  @MapFeature.Require(value = SUPPORTS_REMOVE, absent = ALLOWS_NULL_KEY_QUERIES)
121  public void testRemove_nullQueriesNotSupported() {
122    try {
123      assertNull(
124          "remove(null) should return null or throw NullPointerException", getMap().remove(null));
125    } catch (NullPointerException tolerated) {
126    }
127    expectUnchanged();
128  }
129
130  @MapFeature.Require({SUPPORTS_REMOVE, ALLOWS_NULL_KEY_QUERIES})
131  public void testRemove_nullSupportedMissing() {
132    assertNull("remove(null) should return null", getMap().remove(null));
133    expectUnchanged();
134  }
135
136  @MapFeature.Require(SUPPORTS_REMOVE)
137  public void testRemove_wrongType() {
138    try {
139      assertNull(getMap().remove(WrongType.VALUE));
140    } catch (ClassCastException tolerated) {
141    }
142    expectUnchanged();
143  }
144}