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