/*
 * Copyright (C) 2011 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.testing.MapInterfaceTest;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * Tests for {@link Maps#transformValues} when the backing map's views have iterators that don't
 * support {@code remove()}.
 *
 * @author Jared Levy
 */
@GwtCompatible
public class MapsTransformValuesUnmodifiableIteratorTest extends MapInterfaceTest<String, String> {
  // TODO(jlevy): Move shared code of this class and MapsTransformValuesTest
  // to a superclass.

  public MapsTransformValuesUnmodifiableIteratorTest() {
    super(true, true, false /*supportsPut*/, true, true, false);
  }

  private static class UnmodifiableIteratorMap<K, V> extends ForwardingMap<K, V> {
    final Map<K, V> delegate;

    UnmodifiableIteratorMap(Map<K, V> delegate) {
      this.delegate = delegate;
    }

    @Override
    protected Map<K, V> delegate() {
      return delegate;
    }

    @Override
    public Set<K> keySet() {
      return new ForwardingSet<K>() {
        @Override
        protected Set<K> delegate() {
          return delegate.keySet();
        }

        @Override
        public Iterator<K> iterator() {
          return Iterators.unmodifiableIterator(delegate.keySet().iterator());
        }

        @Override
        public boolean removeAll(Collection<?> c) {
          return delegate.keySet().removeAll(c);
        }

        @Override
        public boolean retainAll(Collection<?> c) {
          return delegate.keySet().retainAll(c);
        }
      };
    }

    @Override
    public Collection<V> values() {
      return new ForwardingCollection<V>() {
        @Override
        protected Collection<V> delegate() {
          return delegate.values();
        }

        @Override
        public Iterator<V> iterator() {
          return Iterators.unmodifiableIterator(delegate.values().iterator());
        }

        @Override
        public boolean removeAll(Collection<?> c) {
          return delegate.values().removeAll(c);
        }

        @Override
        public boolean retainAll(Collection<?> c) {
          return delegate.values().retainAll(c);
        }
      };
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
      return new ForwardingSet<Entry<K, V>>() {
        @Override
        protected Set<Entry<K, V>> delegate() {
          return delegate.entrySet();
        }

        @Override
        public Iterator<Entry<K, V>> iterator() {
          return Iterators.unmodifiableIterator(delegate.entrySet().iterator());
        }

        @Override
        public boolean removeAll(Collection<?> c) {
          return delegate.entrySet().removeAll(c);
        }

        @Override
        public boolean retainAll(Collection<?> c) {
          return delegate.entrySet().retainAll(c);
        }
      };
    }
  }

  @Override
  protected Map<String, String> makeEmptyMap() {
    Map<String, Integer> underlying = Maps.newHashMap();
    return Maps.transformValues(
        new UnmodifiableIteratorMap<String, Integer>(underlying), Functions.toStringFunction());
  }

  @Override
  protected Map<String, String> makePopulatedMap() {
    Map<String, Integer> underlying = Maps.newHashMap();
    underlying.put("a", 1);
    underlying.put("b", 2);
    underlying.put("c", 3);
    return Maps.transformValues(
        new UnmodifiableIteratorMap<String, Integer>(underlying), Functions.toStringFunction());
  }

  @Override
  protected String getKeyNotInPopulatedMap() throws UnsupportedOperationException {
    return "z";
  }

  @Override
  protected String getValueNotInPopulatedMap() throws UnsupportedOperationException {
    return "26";
  }

  /** Helper assertion comparing two maps */
  private void assertMapsEqual(Map<?, ?> expected, Map<?, ?> map) {
    assertEquals(expected, map);
    assertEquals(expected.hashCode(), map.hashCode());
    assertEquals(expected.entrySet(), map.entrySet());

    // Assert that expectedValues > mapValues and that
    // mapValues > expectedValues; i.e. that expectedValues == mapValues.
    Collection<?> expectedValues = expected.values();
    Collection<?> mapValues = map.values();
    assertEquals(expectedValues.size(), mapValues.size());
    assertTrue(expectedValues.containsAll(mapValues));
    assertTrue(mapValues.containsAll(expectedValues));
  }

  public void testTransformEmptyMapEquality() {
    Map<String, String> map =
        Maps.transformValues(ImmutableMap.<String, Integer>of(), Functions.toStringFunction());
    assertMapsEqual(Maps.newHashMap(), map);
  }

  public void testTransformSingletonMapEquality() {
    Map<String, String> map =
        Maps.transformValues(ImmutableMap.of("a", 1), Functions.toStringFunction());
    Map<String, String> expected = ImmutableMap.of("a", "1");
    assertMapsEqual(expected, map);
    assertEquals(expected.get("a"), map.get("a"));
  }

  public void testTransformIdentityFunctionEquality() {
    Map<String, Integer> underlying = ImmutableMap.of("a", 1);
    Map<String, Integer> map = Maps.transformValues(underlying, Functions.<Integer>identity());
    assertMapsEqual(underlying, map);
  }

  public void testTransformPutEntryIsUnsupported() {
    Map<String, String> map =
        Maps.transformValues(ImmutableMap.of("a", 1), Functions.toStringFunction());
    try {
      map.put("b", "2");
      fail();
    } catch (UnsupportedOperationException expected) {
    }

    try {
      map.putAll(ImmutableMap.of("b", "2"));
      fail();
    } catch (UnsupportedOperationException expected) {
    }

    try {
      map.entrySet().iterator().next().setValue("one");
      fail();
    } catch (UnsupportedOperationException expected) {
    }
  }

  public void testTransformRemoveEntry() {
    Map<String, Integer> underlying = Maps.newHashMap();
    underlying.put("a", 1);
    Map<String, String> map = Maps.transformValues(underlying, Functions.toStringFunction());
    assertEquals("1", map.remove("a"));
    assertNull(map.remove("b"));
  }

  public void testTransformEqualityOfMapsWithNullValues() {
    Map<String, String> underlying = Maps.newHashMap();
    underlying.put("a", null);
    underlying.put("b", "");

    Map<String, Boolean> map =
        Maps.transformValues(
            underlying,
            new Function<String, Boolean>() {
              @Override
              public Boolean apply(@NullableDecl String from) {
                return from == null;
              }
            });
    Map<String, Boolean> expected = ImmutableMap.of("a", true, "b", false);
    assertMapsEqual(expected, map);
    assertEquals(expected.get("a"), map.get("a"));
    assertEquals(expected.containsKey("a"), map.containsKey("a"));
    assertEquals(expected.get("b"), map.get("b"));
    assertEquals(expected.containsKey("b"), map.containsKey("b"));
    assertEquals(expected.get("c"), map.get("c"));
    assertEquals(expected.containsKey("c"), map.containsKey("c"));
  }

  public void testTransformReflectsUnderlyingMap() {
    Map<String, Integer> underlying = Maps.newHashMap();
    underlying.put("a", 1);
    underlying.put("b", 2);
    underlying.put("c", 3);
    Map<String, String> map = Maps.transformValues(underlying, Functions.toStringFunction());
    assertEquals(underlying.size(), map.size());

    underlying.put("d", 4);
    assertEquals(underlying.size(), map.size());
    assertEquals("4", map.get("d"));

    underlying.remove("c");
    assertEquals(underlying.size(), map.size());
    assertFalse(map.containsKey("c"));

    underlying.clear();
    assertEquals(underlying.size(), map.size());
  }

  public void testTransformChangesAreReflectedInUnderlyingMap() {
    Map<String, Integer> underlying = Maps.newLinkedHashMap();
    underlying.put("a", 1);
    underlying.put("b", 2);
    underlying.put("c", 3);
    underlying.put("d", 4);
    underlying.put("e", 5);
    underlying.put("f", 6);
    underlying.put("g", 7);
    Map<String, String> map = Maps.transformValues(underlying, Functions.toStringFunction());

    map.remove("a");
    assertFalse(underlying.containsKey("a"));

    Set<String> keys = map.keySet();
    keys.remove("b");
    assertFalse(underlying.containsKey("b"));

    Iterator<String> keyIterator = keys.iterator();
    keyIterator.next();
    keyIterator.remove();
    assertFalse(underlying.containsKey("c"));

    Collection<String> values = map.values();
    values.remove("4");
    assertFalse(underlying.containsKey("d"));

    Iterator<String> valueIterator = values.iterator();
    valueIterator.next();
    valueIterator.remove();
    assertFalse(underlying.containsKey("e"));

    Set<Entry<String, String>> entries = map.entrySet();
    Entry<String, String> firstEntry = entries.iterator().next();
    entries.remove(firstEntry);
    assertFalse(underlying.containsKey("f"));

    Iterator<Entry<String, String>> entryIterator = entries.iterator();
    entryIterator.next();
    entryIterator.remove();
    assertFalse(underlying.containsKey("g"));

    assertTrue(underlying.isEmpty());
    assertTrue(map.isEmpty());
    assertTrue(keys.isEmpty());
    assertTrue(values.isEmpty());
    assertTrue(entries.isEmpty());
  }

  public void testTransformEquals() {
    Map<String, Integer> underlying = ImmutableMap.of("a", 0, "b", 1, "c", 2);
    Map<String, Integer> expected = Maps.transformValues(underlying, Functions.<Integer>identity());

    assertMapsEqual(expected, expected);

    Map<String, Integer> equalToUnderlying = Maps.newTreeMap();
    equalToUnderlying.putAll(underlying);
    Map<String, Integer> map =
        Maps.transformValues(equalToUnderlying, Functions.<Integer>identity());
    assertMapsEqual(expected, map);

    map =
        Maps.transformValues(
            ImmutableMap.of("a", 1, "b", 2, "c", 3),
            new Function<Integer, Integer>() {
              @Override
              public Integer apply(Integer from) {
                return from - 1;
              }
            });
    assertMapsEqual(expected, map);
  }

  public void testTransformEntrySetContains() {
    Map<String, Boolean> underlying = Maps.newHashMap();
    underlying.put("a", null);
    underlying.put("b", true);
    underlying.put(null, true);

    Map<String, Boolean> map =
        Maps.transformValues(
            underlying,
            new Function<Boolean, Boolean>() {
              @Override
              public Boolean apply(@NullableDecl Boolean from) {
                return (from == null) ? true : null;
              }
            });

    Set<Entry<String, Boolean>> entries = map.entrySet();
    assertTrue(entries.contains(Maps.immutableEntry("a", true)));
    assertTrue(entries.contains(Maps.immutableEntry("b", (Boolean) null)));
    assertTrue(entries.contains(Maps.immutableEntry((String) null, (Boolean) null)));

    assertFalse(entries.contains(Maps.immutableEntry("c", (Boolean) null)));
    assertFalse(entries.contains(Maps.immutableEntry((String) null, true)));
  }

  @Override
  public void testKeySetRemoveAllNullFromEmpty() {
    try {
      super.testKeySetRemoveAllNullFromEmpty();
    } catch (RuntimeException tolerated) {
      // GWT's HashMap.keySet().removeAll(null) doesn't throws NPE.
    }
  }

  @Override
  public void testEntrySetRemoveAllNullFromEmpty() {
    try {
      super.testEntrySetRemoveAllNullFromEmpty();
    } catch (RuntimeException tolerated) {
      // GWT's HashMap.entrySet().removeAll(null) doesn't throws NPE.
    }
  }
}
