001/* 002 * Copyright (C) 2016 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.Helpers.getMethod; 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_VALUES; 023import static com.google.common.collect.testing.features.MapFeature.SUPPORTS_PUT; 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.annotations.GwtIncompatible; 029import com.google.common.annotations.J2ktIncompatible; 030import com.google.common.collect.testing.AbstractMapTester; 031import com.google.common.collect.testing.features.CollectionSize; 032import com.google.common.collect.testing.features.MapFeature; 033import com.google.common.collect.testing.testers.TestExceptions.SomeUncheckedException; 034import java.lang.reflect.Method; 035import java.util.Hashtable; 036import java.util.Map; 037import junit.framework.AssertionFailedError; 038 039/** 040 * A generic JUnit test which tests {@link Map#merge}. Can't be invoked directly; please see {@link 041 * com.google.common.collect.testing.MapTestSuiteBuilder}. 042 * 043 * @author Louis Wasserman 044 */ 045@GwtCompatible 046public class MapMergeTester<K, V> extends AbstractMapTester<K, V> { 047 @MapFeature.Require(SUPPORTS_PUT) 048 public void testAbsent() { 049 assertEquals( 050 "Map.merge(absent, value, function) should return value", 051 v3(), 052 getMap() 053 .merge( 054 k3(), 055 v3(), 056 (oldV, newV) -> { 057 throw new AssertionFailedError( 058 "Should not call merge function if key was absent"); 059 })); 060 expectAdded(e3()); 061 } 062 063 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES}) 064 @CollectionSize.Require(absent = ZERO) 065 public void testMappedToNull() { 066 initMapWithNullValue(); 067 assertEquals( 068 "Map.merge(keyMappedToNull, value, function) should return value", 069 v3(), 070 getMap() 071 .merge( 072 getKeyForNullValue(), 073 v3(), 074 (oldV, newV) -> { 075 throw new AssertionFailedError( 076 "Should not call merge function if key was mapped to null"); 077 })); 078 expectReplacement(entry(getKeyForNullValue(), v3())); 079 } 080 081 @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS}) 082 public void testMergeAbsentNullKey() { 083 assertEquals( 084 "Map.merge(null, value, function) should return value", 085 v3(), 086 getMap() 087 .merge( 088 null, 089 v3(), 090 (oldV, newV) -> { 091 throw new AssertionFailedError( 092 "Should not call merge function if key was absent"); 093 })); 094 expectAdded(entry(null, v3())); 095 } 096 097 @MapFeature.Require(SUPPORTS_PUT) 098 @CollectionSize.Require(absent = ZERO) 099 public void testMergePresent() { 100 assertEquals( 101 "Map.merge(present, value, function) should return function result", 102 v4(), 103 getMap() 104 .merge( 105 k0(), 106 v3(), 107 (oldV, newV) -> { 108 assertEquals(v0(), oldV); 109 assertEquals(v3(), newV); 110 return v4(); 111 })); 112 expectReplacement(entry(k0(), v4())); 113 } 114 115 @MapFeature.Require(SUPPORTS_PUT) 116 @CollectionSize.Require(absent = ZERO) 117 public void testMergeFunctionThrows() { 118 assertThrows( 119 SomeUncheckedException.class, 120 () -> 121 getMap() 122 .merge( 123 k0(), 124 v3(), 125 (oldV, newV) -> { 126 assertEquals(v0(), oldV); 127 assertEquals(v3(), newV); 128 throw new SomeUncheckedException(); 129 })); 130 expectUnchanged(); 131 } 132 133 @MapFeature.Require(SUPPORTS_REMOVE) 134 @CollectionSize.Require(absent = ZERO) 135 public void testMergePresentToNull() { 136 assertNull( 137 "Map.merge(present, value, functionReturningNull) should return null", 138 getMap() 139 .merge( 140 k0(), 141 v3(), 142 (oldV, newV) -> { 143 assertEquals(v0(), oldV); 144 assertEquals(v3(), newV); 145 return null; 146 })); 147 expectMissing(e0()); 148 } 149 150 public void testMergeNullValue() { 151 RuntimeException expected = 152 assertThrows( 153 RuntimeException.class, 154 () -> 155 getMap() 156 .merge( 157 k0(), 158 null, 159 (oldV, newV) -> { 160 throw new AssertionFailedError( 161 "Should not call merge function if value was null"); 162 })); 163 if (!(expected instanceof NullPointerException 164 || expected instanceof UnsupportedOperationException)) { 165 throw expected; 166 } 167 } 168 169 public void testMergeNullFunction() { 170 RuntimeException expected = 171 assertThrows(RuntimeException.class, () -> getMap().merge(k0(), v3(), null)); 172 if (!(expected instanceof NullPointerException 173 || expected instanceof UnsupportedOperationException)) { 174 throw expected; 175 } 176 } 177 178 @MapFeature.Require(absent = SUPPORTS_PUT) 179 public void testMergeUnsupported() { 180 assertThrows( 181 UnsupportedOperationException.class, 182 () -> 183 getMap() 184 .merge( 185 k3(), 186 v3(), 187 (oldV, newV) -> { 188 throw new AssertionFailedError(); 189 })); 190 } 191 192 /** 193 * Returns the {@link Method} instance for {@link #testMergeNullValue()} so that tests of {@link 194 * Hashtable} can suppress it with {@code FeatureSpecificTestSuiteBuilder.suppressing()}. 195 */ 196 @J2ktIncompatible 197 @GwtIncompatible // reflection 198 public static Method getMergeNullValueMethod() { 199 return getMethod(MapMergeTester.class, "testMergeNullValue"); 200 } 201}