1 /* 2 * Copyright (C) 2008 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import java.util.Collection; 20 import java.util.Iterator; 21 import java.util.Map; 22 import java.util.Set; 23 24 import javax.annotation.Nullable; 25 26 import com.google.common.annotations.GwtCompatible; 27 import com.google.common.base.Function; 28 import com.google.common.base.Functions; 29 import com.google.common.collect.testing.MapInterfaceTest; 30 31 /** 32 * Tests for {@link Maps#transformValues}. 33 * 34 * @author Isaac Shum 35 */ 36 @GwtCompatible 37 public class MapsTransformValuesTest extends MapInterfaceTest<String, String> { 38 39 /** 40 * Constructor that assigns {@code supportsIteratorRemove} the same value as 41 * {@code supportsRemove}. 42 */ 43 protected MapsTransformValuesTest( 44 boolean allowsNullKeys, 45 boolean allowsNullValues, 46 boolean supportsPut, 47 boolean supportsRemove, 48 boolean supportsClear) { 49 super(allowsNullKeys, allowsNullValues, supportsPut, supportsRemove, 50 supportsClear, supportsRemove); 51 } 52 53 public MapsTransformValuesTest() { 54 super(false, true, false, true, true); 55 } 56 57 protected Map<String, String> makeEmptyMap() { 58 return Maps.transformValues(Maps.<String, String>newHashMap(), 59 Functions.<String>identity()); 60 } 61 62 @Override 63 protected Map<String, String> makePopulatedMap() { 64 Map<String, Integer> underlying = Maps.newHashMap(); 65 underlying.put("a", 1); 66 underlying.put("b", 2); 67 underlying.put("c", 3); 68 return Maps.transformValues(underlying, Functions.toStringFunction()); 69 } 70 71 @Override protected String getKeyNotInPopulatedMap() 72 throws UnsupportedOperationException { 73 return "z"; 74 } 75 76 @Override protected String getValueNotInPopulatedMap() 77 throws UnsupportedOperationException { 78 return "26"; 79 } 80 81 /** Helper assertion comparing two maps */ 82 private void assertMapsEqual(Map<?, ?> expected, Map<?, ?> map) { 83 assertEquals(expected, map); 84 assertEquals(expected.hashCode(), map.hashCode()); 85 assertEquals(expected.entrySet(), map.entrySet()); 86 87 // Assert that expectedValues > mapValues and that 88 // mapValues > expectedValues; i.e. that expectedValues == mapValues. 89 Collection<?> expectedValues = expected.values(); 90 Collection<?> mapValues = map.values(); 91 assertEquals(expectedValues.size(), mapValues.size()); 92 assertTrue(expectedValues.containsAll(mapValues)); 93 assertTrue(mapValues.containsAll(expectedValues)); 94 } 95 96 public void testTransformEmptyMapEquality() { 97 Map<String, String> map = Maps.transformValues( 98 ImmutableMap.<String, Integer>of(), Functions.toStringFunction()); 99 assertMapsEqual(Maps.newHashMap(), map); 100 } 101 102 public void testTransformSingletonMapEquality() { 103 Map<String, String> map = Maps.transformValues( 104 ImmutableMap.of("a", 1), Functions.toStringFunction()); 105 Map<String, String> expected = ImmutableMap.of("a", "1"); 106 assertMapsEqual(expected, map); 107 assertEquals(expected.get("a"), map.get("a")); 108 } 109 110 public void testTransformIdentityFunctionEquality() { 111 Map<String, Integer> underlying = ImmutableMap.of("a", 1); 112 Map<String, Integer> map = Maps.transformValues( 113 underlying, Functions.<Integer>identity()); 114 assertMapsEqual(underlying, map); 115 } 116 117 public void testTransformPutEntryIsUnsupported() { 118 Map<String, String> map = Maps.transformValues( 119 ImmutableMap.of("a", 1), Functions.toStringFunction()); 120 try { 121 map.put("b", "2"); 122 fail(); 123 } catch (UnsupportedOperationException expected) { 124 } 125 126 try { 127 map.putAll(ImmutableMap.of("b", "2")); 128 fail(); 129 } catch (UnsupportedOperationException expected) { 130 } 131 132 try { 133 map.entrySet().iterator().next().setValue("one"); 134 fail(); 135 } catch (UnsupportedOperationException expected) { 136 } 137 } 138 139 public void testTransformRemoveEntry() { 140 Map<String, Integer> underlying = Maps.newHashMap(); 141 underlying.put("a", 1); 142 Map<String, String> map 143 = Maps.transformValues(underlying, Functions.toStringFunction()); 144 assertEquals("1", map.remove("a")); 145 assertNull(map.remove("b")); 146 } 147 148 public void testTransformEqualityOfMapsWithNullValues() { 149 Map<String, String> underlying = Maps.newHashMap(); 150 underlying.put("a", null); 151 underlying.put("b", ""); 152 153 Map<String, Boolean> map = Maps.transformValues(underlying, 154 new Function<String, Boolean>() { 155 @Override 156 public Boolean apply(@Nullable String from) { 157 return from == null; 158 } 159 } 160 ); 161 Map<String, Boolean> expected = ImmutableMap.of("a", true, "b", false); 162 assertMapsEqual(expected, map); 163 assertEquals(expected.get("a"), map.get("a")); 164 assertEquals(expected.containsKey("a"), map.containsKey("a")); 165 assertEquals(expected.get("b"), map.get("b")); 166 assertEquals(expected.containsKey("b"), map.containsKey("b")); 167 assertEquals(expected.get("c"), map.get("c")); 168 assertEquals(expected.containsKey("c"), map.containsKey("c")); 169 } 170 171 public void testTransformReflectsUnderlyingMap() { 172 Map<String, Integer> underlying = Maps.newHashMap(); 173 underlying.put("a", 1); 174 underlying.put("b", 2); 175 underlying.put("c", 3); 176 Map<String, String> map 177 = Maps.transformValues(underlying, Functions.toStringFunction()); 178 assertEquals(underlying.size(), map.size()); 179 180 underlying.put("d", 4); 181 assertEquals(underlying.size(), map.size()); 182 assertEquals("4", map.get("d")); 183 184 underlying.remove("c"); 185 assertEquals(underlying.size(), map.size()); 186 assertFalse(map.containsKey("c")); 187 188 underlying.clear(); 189 assertEquals(underlying.size(), map.size()); 190 } 191 192 public void testTransformChangesAreReflectedInUnderlyingMap() { 193 Map<String, Integer> underlying = Maps.newLinkedHashMap(); 194 underlying.put("a", 1); 195 underlying.put("b", 2); 196 underlying.put("c", 3); 197 underlying.put("d", 4); 198 underlying.put("e", 5); 199 underlying.put("f", 6); 200 underlying.put("g", 7); 201 Map<String, String> map 202 = Maps.transformValues(underlying, Functions.toStringFunction()); 203 204 map.remove("a"); 205 assertFalse(underlying.containsKey("a")); 206 207 Set<String> keys = map.keySet(); 208 keys.remove("b"); 209 assertFalse(underlying.containsKey("b")); 210 211 Iterator<String> keyIterator = keys.iterator(); 212 keyIterator.next(); 213 keyIterator.remove(); 214 assertFalse(underlying.containsKey("c")); 215 216 Collection<String> values = map.values(); 217 values.remove("4"); 218 assertFalse(underlying.containsKey("d")); 219 220 Iterator<String> valueIterator = values.iterator(); 221 valueIterator.next(); 222 valueIterator.remove(); 223 assertFalse(underlying.containsKey("e")); 224 225 Set<Map.Entry<String, String>> entries = map.entrySet(); 226 Map.Entry<String, String> firstEntry = entries.iterator().next(); 227 entries.remove(firstEntry); 228 assertFalse(underlying.containsKey("f")); 229 230 Iterator<Map.Entry<String, String>> entryIterator = entries.iterator(); 231 entryIterator.next(); 232 entryIterator.remove(); 233 assertFalse(underlying.containsKey("g")); 234 235 assertTrue(underlying.isEmpty()); 236 assertTrue(map.isEmpty()); 237 assertTrue(keys.isEmpty()); 238 assertTrue(values.isEmpty()); 239 assertTrue(entries.isEmpty()); 240 } 241 242 public void testTransformEquals() { 243 Map<String, Integer> underlying = ImmutableMap.of("a", 0, "b", 1, "c", 2); 244 Map<String, Integer> expected 245 = Maps.transformValues(underlying, Functions.<Integer>identity()); 246 247 assertMapsEqual(expected, expected); 248 249 Map<String, Integer> equalToUnderlying = Maps.newTreeMap(); 250 equalToUnderlying.putAll(underlying); 251 Map<String, Integer> map = Maps.transformValues( 252 equalToUnderlying, Functions.<Integer>identity()); 253 assertMapsEqual(expected, map); 254 255 map = Maps.transformValues(ImmutableMap.of("a", 1, "b", 2, "c", 3), 256 new Function<Integer, Integer>() { 257 @Override 258 public Integer apply(Integer from) { 259 return from - 1; 260 } 261 } 262 ); 263 assertMapsEqual(expected, map); 264 } 265 266 public void testTransformEntrySetContains() { 267 Map<String, Boolean> underlying = Maps.newHashMap(); 268 underlying.put("a", null); 269 underlying.put("b", true); 270 underlying.put(null, true); 271 272 Map<String, Boolean> map = Maps.transformValues( 273 underlying, new Function<Boolean, Boolean>() { 274 @Override 275 public Boolean apply(@Nullable Boolean from) { 276 return (from == null) ? true : null; 277 } 278 } 279 ); 280 281 Set<Map.Entry<String, Boolean>> entries = map.entrySet(); 282 assertTrue(entries.contains(Maps.immutableEntry("a", true))); 283 assertTrue(entries.contains(Maps.immutableEntry("b", (Boolean) null))); 284 assertTrue(entries.contains( 285 Maps.immutableEntry((String) null, (Boolean) null))); 286 287 assertFalse(entries.contains(Maps.immutableEntry("c", (Boolean) null))); 288 assertFalse(entries.contains(Maps.immutableEntry((String) null, true))); 289 } 290 291 @Override public void testKeySetRemoveAllNullFromEmpty() { 292 try { 293 super.testKeySetRemoveAllNullFromEmpty(); 294 } catch (RuntimeException tolerated) { 295 // GWT's HashMap.keySet().removeAll(null) doesn't throws NPE. 296 } 297 } 298 299 @Override public void testEntrySetRemoveAllNullFromEmpty() { 300 try { 301 super.testEntrySetRemoveAllNullFromEmpty(); 302 } catch (RuntimeException tolerated) { 303 // GWT's HashMap.entrySet().removeAll(null) doesn't throws NPE. 304 } 305 } 306 } 307