// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.google.protobuf;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import junit.framework.TestCase;

/**
 * @author darick@google.com Darick Tong
 */
public class SmallSortedMapTest extends TestCase {
  // java.util.AbstractMap.SimpleEntry is private in JDK 1.5. We re-implement it
  // here for JDK 1.5 users.
  private static class SimpleEntry<K, V> implements Map.Entry<K, V> {
    private final K key;
    private V value;

    SimpleEntry(K key, V value) {
      this.key = key;
      this.value = value;
    }

    @Override
    public K getKey() {
      return key;
    }

    @Override
    public V getValue() {
      return value;
    }

    @Override
    public V setValue(V value) {
      V oldValue = this.value;
      this.value = value;
      return oldValue;
    }

    private static boolean eq(Object o1, Object o2) {
      return o1 == null ? o2 == null : o1.equals(o2);
    }

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof Map.Entry))
        return false;
      Map.Entry e = (Map.Entry) o;
      return eq(key, e.getKey()) && eq(value, e.getValue());
    }

    @Override
    public int hashCode() {
      return ((key == null) ? 0 : key.hashCode()) ^
          ((value == null) ? 0 : value.hashCode());
    }
  }

  public void testPutAndGetArrayEntriesOnly() {
    runPutAndGetTest(3);
  }

  public void testPutAndGetOverflowEntries() {
    runPutAndGetTest(6);
  }

  private void runPutAndGetTest(int numElements) {
    // Test with even and odd arraySize
    SmallSortedMap<Integer, Integer> map1 =
        SmallSortedMap.newInstanceForTest(3);
    SmallSortedMap<Integer, Integer> map2 =
        SmallSortedMap.newInstanceForTest(4);
    SmallSortedMap<Integer, Integer> map3 =
        SmallSortedMap.newInstanceForTest(3);
    SmallSortedMap<Integer, Integer> map4 =
        SmallSortedMap.newInstanceForTest(4);

    // Test with puts in ascending order.
    for (int i = 0; i < numElements; i++) {
      assertNull(map1.put(i, i + 1));
      assertNull(map2.put(i, i + 1));
    }
    // Test with puts in descending order.
    for (int i = numElements - 1; i >= 0; i--) {
      assertNull(map3.put(i, i + 1));
      assertNull(map4.put(i, i + 1));
    }

    assertEquals(Math.min(3, numElements), map1.getNumArrayEntries());
    assertEquals(Math.min(4, numElements), map2.getNumArrayEntries());
    assertEquals(Math.min(3, numElements), map3.getNumArrayEntries());
    assertEquals(Math.min(4, numElements), map4.getNumArrayEntries());

    List<SmallSortedMap<Integer, Integer>> allMaps =
        new ArrayList<SmallSortedMap<Integer, Integer>>();
    allMaps.add(map1);
    allMaps.add(map2);
    allMaps.add(map3);
    allMaps.add(map4);

    for (SmallSortedMap<Integer, Integer> map : allMaps) {
      assertEquals(numElements, map.size());
      for (int i = 0; i < numElements; i++) {
        assertEquals(new Integer(i + 1), map.get(i));
      }
    }

    assertEquals(map1, map2);
    assertEquals(map2, map3);
    assertEquals(map3, map4);
  }

  public void testReplacingPut() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
      assertNull(map.remove(i + 1));
    }
    for (int i = 0; i < 6; i++) {
      assertEquals(new Integer(i + 1), map.put(i, i + 2));
    }
  }

  public void testRemove() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
      assertNull(map.remove(i + 1));
    }

    assertEquals(3, map.getNumArrayEntries());
    assertEquals(3, map.getNumOverflowEntries());
    assertEquals(6,  map.size());
    assertEquals(makeSortedKeySet(0, 1, 2, 3, 4, 5), map.keySet());

    assertEquals(new Integer(2), map.remove(1));
    assertEquals(3, map.getNumArrayEntries());
    assertEquals(2, map.getNumOverflowEntries());
    assertEquals(5,  map.size());
    assertEquals(makeSortedKeySet(0, 2, 3, 4, 5), map.keySet());

    assertEquals(new Integer(5), map.remove(4));
    assertEquals(3, map.getNumArrayEntries());
    assertEquals(1, map.getNumOverflowEntries());
    assertEquals(4,  map.size());
    assertEquals(makeSortedKeySet(0, 2, 3, 5), map.keySet());

    assertEquals(new Integer(4), map.remove(3));
    assertEquals(3, map.getNumArrayEntries());
    assertEquals(0, map.getNumOverflowEntries());
    assertEquals(3, map.size());
    assertEquals(makeSortedKeySet(0, 2, 5), map.keySet());

    assertNull(map.remove(3));
    assertEquals(3, map.getNumArrayEntries());
    assertEquals(0, map.getNumOverflowEntries());
    assertEquals(3, map.size());

    assertEquals(new Integer(1), map.remove(0));
    assertEquals(2, map.getNumArrayEntries());
    assertEquals(0, map.getNumOverflowEntries());
    assertEquals(2, map.size());
  }

  public void testClear() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    map.clear();
    assertEquals(0, map.getNumArrayEntries());
    assertEquals(0, map.getNumOverflowEntries());
    assertEquals(0, map.size());
  }

  public void testGetArrayEntryAndOverflowEntries() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    assertEquals(3, map.getNumArrayEntries());
    for (int i = 0; i < 3; i++) {
      Map.Entry<Integer, Integer> entry = map.getArrayEntryAt(i);
      assertEquals(new Integer(i), entry.getKey());
      assertEquals(new Integer(i + 1), entry.getValue());
    }
    Iterator<Map.Entry<Integer, Integer>> it =
        map.getOverflowEntries().iterator();
    for (int i = 3; i < 6; i++) {
      assertTrue(it.hasNext());
      Map.Entry<Integer, Integer> entry = it.next();
      assertEquals(new Integer(i), entry.getKey());
      assertEquals(new Integer(i + 1), entry.getValue());
    }
    assertFalse(it.hasNext());
  }

  public void testEntrySetContains() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
    for (int i = 0; i < 6; i++) {
      assertTrue(
          entrySet.contains(new SimpleEntry<Integer, Integer>(i, i + 1)));
      assertFalse(
          entrySet.contains(new SimpleEntry<Integer, Integer>(i, i)));
    }
  }

  public void testEntrySetAdd() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
    for (int i = 0; i < 6; i++) {
      Map.Entry<Integer, Integer> entry =
          new SimpleEntry<Integer, Integer>(i, i + 1);
      assertTrue(entrySet.add(entry));
      assertFalse(entrySet.add(entry));
    }
    for (int i = 0; i < 6; i++) {
      assertEquals(new Integer(i + 1), map.get(i));
    }
    assertEquals(3, map.getNumArrayEntries());
    assertEquals(3, map.getNumOverflowEntries());
    assertEquals(6, map.size());
  }

  public void testEntrySetRemove() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    for (int i = 0; i < 6; i++) {
      Map.Entry<Integer, Integer> entry =
          new SimpleEntry<Integer, Integer>(i, i + 1);
      assertTrue(entrySet.remove(entry));
      assertFalse(entrySet.remove(entry));
    }
    assertTrue(map.isEmpty());
    assertEquals(0, map.getNumArrayEntries());
    assertEquals(0, map.getNumOverflowEntries());
    assertEquals(0, map.size());
  }

  public void testEntrySetClear() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    map.entrySet().clear();
    assertTrue(map.isEmpty());
    assertEquals(0, map.getNumArrayEntries());
    assertEquals(0, map.getNumOverflowEntries());
    assertEquals(0, map.size());
  }

  public void testEntrySetIteratorNext() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    for (int i = 0; i < 6; i++) {
      assertTrue(it.hasNext());
      Map.Entry<Integer, Integer> entry = it.next();
      assertEquals(new Integer(i), entry.getKey());
      assertEquals(new Integer(i + 1), entry.getValue());
    }
    assertFalse(it.hasNext());
  }

  public void testEntrySetIteratorRemove() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    for (int i = 0; i < 6; i++) {
      assertTrue(map.containsKey(i));
      it.next();
      it.remove();
      assertFalse(map.containsKey(i));
      assertEquals(6 - i - 1, map.size());
    }
  }

  public void testMapEntryModification() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    for (int i = 0; i < 6; i++) {
      Map.Entry<Integer, Integer> entry = it.next();
      entry.setValue(i + 23);
    }
    for (int i = 0; i < 6; i++) {
      assertEquals(new Integer(i + 23), map.get(i));
    }
  }

  public void testMakeImmutable() {
    SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
    for (int i = 0; i < 6; i++) {
      assertNull(map.put(i, i + 1));
    }
    map.makeImmutable();
    assertEquals(new Integer(1), map.get(0));
    assertEquals(6, map.size());

    try {
      map.put(23, 23);
      fail("Expected UnsupportedOperationException");
    } catch (UnsupportedOperationException expected) {
    }

    Map<Integer, Integer> other = new HashMap<Integer, Integer>();
    other.put(23, 23);
    try {
      map.putAll(other);
      fail("Expected UnsupportedOperationException");
    } catch (UnsupportedOperationException expected) {
    }

    try {
      map.remove(0);
      fail("Expected UnsupportedOperationException");
    } catch (UnsupportedOperationException expected) {
    }

    try {
      map.clear();
      fail("Expected UnsupportedOperationException");
    } catch (UnsupportedOperationException expected) {
    }

    Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
    try {
      entrySet.clear();
      fail("Expected UnsupportedOperationException");
    } catch (UnsupportedOperationException expected) {
    }

    Iterator<Map.Entry<Integer, Integer>> it = entrySet.iterator();
    while (it.hasNext()) {
      Map.Entry<Integer, Integer> entry = it.next();
      try {
        entry.setValue(0);
        fail("Expected UnsupportedOperationException");
      } catch (UnsupportedOperationException expected) {
      }
      try {
        it.remove();
        fail("Expected UnsupportedOperationException");
      } catch (UnsupportedOperationException expected) {
      }
    }

    Set<Integer> keySet = map.keySet();
    try {
      keySet.clear();
      fail("Expected UnsupportedOperationException");
    } catch (UnsupportedOperationException expected) {
    }

    Iterator<Integer> keys = keySet.iterator();
    while (keys.hasNext()) {
      Integer key = keys.next();
      try {
        keySet.remove(key);
        fail("Expected UnsupportedOperationException");
      } catch (UnsupportedOperationException expected) {
      }
      try {
        keys.remove();
        fail("Expected UnsupportedOperationException");
      } catch (UnsupportedOperationException expected) {
      }
    }
  }

  private Set<Integer> makeSortedKeySet(Integer... keys) {
    return new TreeSet<Integer>(Arrays.<Integer>asList(keys));
  }
}
