Home | History | Annotate | Download | only in collect
      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